diff --git a/modules/json_form_widget/README.md b/modules/json_form_widget/README.md
new file mode 100644
index 0000000000..51d4748d63
--- /dev/null
+++ b/modules/json_form_widget/README.md
@@ -0,0 +1,100 @@
+## High level
+
+```mermaid
+sequenceDiagram
+ participant FormBuilder
+ participant FieldTypeRouter
+ participant Element Handlers
+ participant SchemaUiHandler
+
+ loop each $property in $form
+ FormBuilder ->> FieldTypeRouter: getFormElement()
+ FieldTypeRouter ->> Element Handlers: handler functions
on helper classes
+ Note over FieldTypeRouter, Element Handlers: Initial build of property
Elements
+ Element Handlers ->> FormBuilder: Return default element for $property
+ end
+
+ FormBuilder ->> SchemaUiHandler: applySchemaUi()
+ Note over FormBuilder, SchemaUiHandler: Now apply SchemaUi to full $form
+ loop each $property
+ SchemaUiHandler ->> SchemaUiHandler: applyOnBaseField()
+ SchemaUiHandler ->> SchemaUiHandler: handlePropertySpec()
+ Note over SchemaUiHandler, SchemaUiHandler: See handlePropertySpec()
internals diagram
+ end
+ SchemaUiHandler ->> FormBuilder: Return $form with SchemaUi alterations
+
+```
+
+## The handlePropertySpec() method
+
+As called from withing SchemaUiHandler::applyShemaUi
+
+```mermaid
+sequenceDiagram
+ participant handlePropertySpec
+
+
+```
+
+## The initial build
+
+```mermaid
+graph TD
+ getForm["FormBuilder::getJsonForm()"] --> eachProp["foreach $properties"]
+ eachProp --> getElement["FieldTypeRouter::getFormElement()"]
+ getElement --> switch[Switch $type]
+ switch --> object{object}
+
+ object -- true --> handleObject["ObjectHelper::handleObjectElement()"]
+ handleObject --> generateObject["ObjectHelper::generateObjectElement()"]
+ generateObject --> generateProperties["ObjectHelper::generateProperties()"]
+ generateProperties -- recursion --> eachProp
+
+
+ object -- false --> array{array}
+ array -- true --> handleArray["ArrayHelper::handleArrayElement()"]
+ handleArray --> complex{Items are objects?}
+ complex -- no --> buildSimple["ArrayHelper::buildSimpleArrayElement()"]
+ complex -- yes --> buildComplex["ArrayHelper::buildComplexArrayElement()"]
+ buildComplex --> handleObject
+
+ array -- false --> string["string"]
+ string -- true --> handleString["StringHelper::handleStringElement()"]
+ string -- false --> integer["integer"]
+ integer -- true --> handleInteger["IntegerHelper::handleIntegerElement()"]
+ switch --> eachProp
+ eachProp --> getForm
+```
+
+## Customizing widgets w/SchemaUI
+
+```mermaid
+flowchart-elk TD
+ getForm["FormBuilder::getJsonForm()"] --> applySchemaUi["SchemaUiHandler::applySchemaUi()"]
+ applySchemaUi --> eachProp2["foreach schemaUI property"]
+ eachProp2 --> applyOnBaseField["SchemaUiHandler::applyOnBaseField()"]
+ eachProp2 --> handlePropertySpec
+ subgraph s1["applyOnBaseField()"]
+ applyOnBaseField --> updateWidgets["SchemaUiHandler::updatewidgets()"]
+ updateWidgets --> disableFields["SchemaUiHandler::disableFields()"]
+ disableFields --> addPlaceholders["SchemaUiHandler::addPlaceholders()"]
+ addPlaceholders --> changeFieldDescriptions["SchemaUiHandler::changeFieldDescriptions()"]
+ changeFieldDescriptions --> changeFieldTitle["SchemaUiHandler::changeFieldTitle()"]
+ end
+ subgraph s2["handlePropertySpec"]
+ handlePropertySpec["SchemaUiHandler::handlePropertySpec()"] --> what{"what is it"}
+ what -- array --> eachArrayElement
+ eachArrayElement --> applyOnArrayFields
+
+ applyOnArrayFields --> eachArrayElementField
+ eachArrayElementField --> inSpec{"Does SchemaUI
contain config for
this field?"}
+ inSpec -- yes --> handlePropertySpec
+ inSpec -- no --> applyOnBaseFieldRec["SchemaUiHandler::applyOnBaseField()"]
+
+ what -- object --> applyOnObjectFields
+ applyOnObjectFields --> eachObjField["foreach object property in the SchemaUi spec"]
+ eachObjField --> applyOnBaseFieldRec
+
+ end
+
+```
diff --git a/modules/json_form_widget/json_form_widget.module b/modules/json_form_widget/json_form_widget.module
index 444a8d4849..ccdef19e86 100644
--- a/modules/json_form_widget/json_form_widget.module
+++ b/modules/json_form_widget/json_form_widget.module
@@ -35,7 +35,7 @@ function json_form_widget_remove_one(array &$form, FormStateInterface $form_stat
/**
* Update count property by the given offset.
*
- * @param FormStateInterface $form_state
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
* Form state.
* @param int $offset
* Offset to change count by.
diff --git a/modules/json_form_widget/src/ArrayHelper.php b/modules/json_form_widget/src/ArrayHelper.php
index 09b13e19fe..05900610ce 100644
--- a/modules/json_form_widget/src/ArrayHelper.php
+++ b/modules/json_form_widget/src/ArrayHelper.php
@@ -2,9 +2,10 @@
namespace Drupal\json_form_widget;
-use Drupal\Core\Form\FormStateInterface;
+use Drupal\Component\Utility\NestedArray;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
+use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -30,9 +31,7 @@ class ArrayHelper implements ContainerInjectionInterface {
public FieldTypeRouter $builder;
/**
- * Inherited.
- *
- * @{inheritdocs}
+ * {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
@@ -56,7 +55,7 @@ public function setBuilder(FieldTypeRouter $builder): void {
}
/**
- * Update wrapper element of the triggering button after build.
+ * Shared AJAX callback function for all array buttons.
*
* @param array $form
* Newly built form render array.
@@ -66,7 +65,7 @@ public function setBuilder(FieldTypeRouter $builder): void {
* @return array
* Field wrapper render array.
*/
- public function addOrRemoveButtonCallback(array &$form, FormStateInterface $form_state): array {
+ public function arrayActionButtonCallback(array &$form, FormStateInterface $form_state): array {
// Retrieve triggering button element.
$button = $form_state->getTriggeringElement();
// Extract full heritage for the triggered button.
@@ -96,37 +95,136 @@ public function addOrRemoveButtonCallback(array &$form, FormStateInterface $form
* Handle form element for an array.
*/
public function handleArrayElement(array $definition, ?array $data, FormStateInterface $form_state, array $context): array {
- // Extract field name from field definition and min items from field schema
- // for later reference.
+ // Extract field name from field definition and min items from field schema.
$field_name = $definition['name'];
$min_items = $definition['schema']->minItems ?? 0;
- // Build context name.
+
$context_name = self::buildContextName($context);
- // Determine number of form items to generate.
$item_count = $this->getItemCount($context_name, count($data ?? []), $min_items, $form_state);
+ $is_required = in_array($field_name, $this->builder->getSchema()->required ?? []);
- // Determine if this field is required.
- $required_fields = $this->builder->getSchema()->required ?? [];
- $field_required = in_array($field_name, $required_fields);
// Build the specified number of field item elements.
- $field_properties = [];
+ $items = [];
for ($i = 0; $i < $item_count; $i++) {
- $property_required = $field_required && ($i < $min_items);
- $field_properties[] = $this->buildArrayElement($definition, $data[$i] ?? NULL, $form_state, array_merge($context, [$i]), $property_required);
+ $property_required = $is_required && ($i < $min_items);
+ $items[] = $this->buildArrayItemElement($definition, $data[$i] ?? NULL, $form_state, array_merge($context, [$i]), $property_required);
}
// Build field element.
- return [
- '#type' => 'fieldset',
- '#title' => ($definition['schema']->title ?? $field_name),
- '#description' => ($definition['schema']->description ?? ''),
+ $element = [
+ '#type' => 'fieldset',
+ '#title' => ($definition['schema']->title ?? $field_name),
+ '#description' => ($definition['schema']->description ?? ''),
'#description_display' => 'before',
- '#prefix' => '
',
- '#suffix' => '
',
- '#tree' => TRUE,
- 'actions' => $this->buildActions($item_count, $min_items, $field_name, $context_name),
- $field_name => $field_properties,
+ '#prefix' => '',
+ '#suffix' => '
',
+ '#tree' => TRUE,
+ '#required' => $is_required,
+ 'actions' => [
+ '#type' => 'actions',
+ 'actions' => [
+ 'add' => $this->buildAction($this->t('Add one'), 'addOne', $field_name, $context_name),
+ ],
+ ],
+ $field_name => $items,
];
+ return $element;
+ }
+
+ /**
+ * Build a single element from an array.
+ *
+ * @param array $definition
+ * Field definition.
+ * @param mixed $data
+ * Field data.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ * Form state.
+ * @param string[] $context
+ * Field context.
+ * @param bool $required
+ * Whether the field is required.
+ *
+ * @return array
+ * Render array for the array element.
+ */
+ protected function buildArrayItemElement(array $definition, $data, FormStateInterface $form_state, array $context, bool $required): array {
+ // Use the simple or complex method depending on whether items are objects.
+ if (isset($definition['schema']->items->properties)) {
+ $element = $this->buildComplexArrayElement($definition, $data, $form_state, $context);
+ }
+ else {
+ $element = $this->buildSimpleArrayElement($definition, $data, $context);
+ }
+ // If we show the element on the form, it's required.
+ $element['#required'] = $required;
+ return $element;
+ }
+
+ /**
+ * Returns single simple element from array.
+ *
+ * @param array $definition
+ * Field definition.
+ * @param mixed $data
+ * Field data.
+ * @param string[] $context
+ * Field context.
+ *
+ * @return array
+ * Render array for the simple array element.
+ */
+ protected function buildSimpleArrayElement(array $definition, $data, array $context): array {
+ return [
+ '#type' => 'fieldset',
+ '#attributes' => [
+ 'data-parent' => $definition['name'],
+ 'class' => ['json-form-widget-array-item'],
+ ],
+ 'field' => array_filter([
+ '#type' => 'textfield',
+ '#title' => $definition['schema']->items->title ?? NULL,
+ '#default_value' => $data,
+ ]),
+ 'actions' => $this->buildElementActions($definition['name'], self::buildContextName($context)),
+ ];
+ }
+
+ /**
+ * Flatten array element fieldset w/buttons for processing.
+ *
+ * @param array $element
+ * A form element.
+ */
+ public static function flattenArrayElementFieldset(array &$element): void {
+ if (isset($element['field']) && $element['#type'] == 'fieldset') {
+ $element = ['#required' => ($element['#required'] ?? FALSE)] + $element['field'];
+ }
+ }
+
+ /**
+ * Returns single complex element from array.
+ *
+ * @param array $definition
+ * Field definition.
+ * @param mixed $data
+ * Field data.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ * Form state.
+ * @param string[] $context
+ * Field context.
+ *
+ * @return array
+ * Render array for the complex array element.
+ */
+ protected function buildComplexArrayElement(array $definition, $data, FormStateInterface $form_state, array $context): array {
+ $subdefinition = [
+ 'name' => $definition['name'],
+ 'schema' => $definition['schema']->items,
+ ];
+ $element = $this->objectHelper->handleObjectElement($subdefinition, $data, $form_state, $context, $this->builder);
+ $element[$definition['name']]['actions'] = $this->buildElementActions($definition['name'], self::buildContextName($context));
+ return $element;
}
/**
@@ -200,85 +298,182 @@ public static function buildCountProperty(string $context_name): array {
}
/**
- * Helper function to build form field actions.
- */
- protected function buildActions(int $item_count, int $min_items, string $parent, string $context_name): array {
- $actions = [];
-
- // Build add action.
- $actions['add'] = $this->buildAction($this->t('Add one'), 'json_form_widget_add_one', $parent, $context_name);
- // Build remove action if there are more than the minimum required elements
- // in this field array.
- if ($item_count > $min_items) {
- $actions['remove'] = $this->buildAction($this->t('Remove one'), 'json_form_widget_remove_one', $parent, $context_name);
- }
-
- return [
- '#type' => 'actions',
- 'actions' => $actions,
- ];
- }
-
- /**
- * Helper function to get action.
+ * Helper function to build an action button.
+ *
+ * @param string $title
+ * Button title.
+ * @param string $method
+ * Button submit method; should be a static method from this class.
+ * @param string $parent
+ * The parent element for the action; usually the current field name.
+ * @param string $context_name
+ * The context name, output of ::buildContextName().
*/
- protected function buildAction(string $title, string $function, string $parent, string $context_name): array {
- return [
+ protected function buildAction(string $title, string $method, string $parent, string $context_name): array {
+ $action = [
'#type' => 'submit',
'#name' => $context_name,
'#value' => $title,
- '#submit' => [$function],
+ '#submit' => [self::class . '::' . $method],
'#ajax' => [
- 'callback' => [$this, 'addOrRemoveButtonCallback'],
- 'wrapper' => self::buildWrapperIdentifier($context_name),
+ 'callback' => [$this, 'arrayActionButtonCallback'],
+ 'wrapper' => self::buildWrapperIdentifier($parent),
],
'#attributes' => [
'data-parent' => $parent,
- 'data-context' => $context_name,
],
'#limit_validation_errors' => [],
];
+ return $action;
}
/**
- * Handle single element from array.
+ * Build the remove/reorder actions for a single element.
+ *
+ * @param string $parent
+ * Parent element name.
+ * @param string $context_name
+ * Data context.
*
- * Chooses whether element is simple or complex.
+ * @return array{#type: string, remove: array}
+ * Actions render array.
*/
- protected function buildArrayElement(array $definition, $data, FormStateInterface $form_state, array $context, bool $required): array {
- // If this element's definition has properties defined...
- $element = isset($definition['schema']->items->properties) ?
- // Attempt to build a complex element, otherwise...
- $this->buildComplexArrayElement($definition, $data, $form_state, $context) :
- // Build a simple element.
- $this->buildSimpleArrayElement($definition, $data);
-
- // Set element requirement.
- $element['#required'] = $required;
+ protected function buildElementActions(string $parent, string $context_name) {
+ return [
+ '#type' => 'actions',
+ 'remove' => $this->buildAction($this->t('Remove'), 'remove', $parent, $context_name),
+ 'move_up' => $this->buildAction($this->t('Move Up'), 'moveUp', $parent, $context_name),
+ 'move_down' => $this->buildAction($this->t('Move Down'), 'moveDown', $parent, $context_name),
+ ];
+ }
- return $element;
+ /**
+ * Submit function for element "remove" button.
+ *
+ * @param array $form
+ * Form render array.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ * Form state.
+ */
+ public static function remove(array &$form, FormStateInterface $form_state) {
+ $button_element = $form_state->getTriggeringElement();
+ $parent = $button_element['#attributes']['data-parent'];
+ $parents = $button_element['#parents'];
+ $element_index = str_replace("{$parent}-", '', $button_element['#name']);
+ $count_property = self::buildCountProperty($parent);
+ $user_input = $form_state->getUserInput();
+
+ // Update the user input to remove the specific element.
+ $key_exists = NULL;
+ static::trimParents($parents, $element_index);
+ $input_values = &NestedArray::getValue($user_input, $parents, $key_exists);
+ if ($key_exists) {
+ unset($input_values[$element_index]);
+ // Re-index the array to maintain proper keys.
+ $input_values = \array_values($input_values);
+ }
+
+ $form_state->setUserInput($user_input);
+
+ // Modify stored item count. The form rebuilds before the alter, so it needs
+ // to be one more than the current item count to avoid removing twice.
+ $item_count = count($input_values);
+ $form_state->set($count_property, $item_count);
+
+ $form_state->setRebuild();
}
/**
- * Returns single simple element from array.
+ * Submit function for element "move up" button.
+ *
+ * @param array $form
+ * Form render array.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ * Form state.
*/
- protected function buildSimpleArrayElement(array $definition, $data): array {
- return array_filter([
- '#type' => 'textfield',
- '#title' => $definition['schema']->items->title ?? NULL,
- '#default_value' => $data,
- ]);
+ public static function moveUp(array &$form, FormStateInterface $form_state) {
+ return static::moveElement($form_state, -1);
}
/**
- * Returns single complex element from array.
+ * Submit function for element "move down" button.
+ *
+ * @param array $form
+ * Form render array.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ * Form state.
*/
- protected function buildComplexArrayElement(array $definition, $data, FormStateInterface $form_state, array $context): array {
- $subdefinition = [
- 'name' => $definition['name'],
- 'schema' => $definition['schema']->items,
- ];
- return $this->objectHelper->handleObjectElement($subdefinition, $data, $form_state, $context, $this->builder);
+ public static function moveDown(array &$form, FormStateInterface $form_state) {
+ return static::moveElement($form_state, 1);
+ }
+
+ /**
+ * Common function to move element within array by the given offset.
+ *
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ * Form state.
+ * @param int $offset
+ * Offset to move the element by.
+ */
+ protected static function moveElement(FormStateInterface $form_state, int $offset) {
+ $button_element = $form_state->getTriggeringElement();
+ $parent = $button_element['#attributes']['data-parent'];
+ $parents = $button_element['#parents'];
+ $element_index = str_replace("{$parent}-", '', $button_element['#name']);
+ $user_input = $form_state->getUserInput();
+
+ // Update the user input to change the order.
+ $key_exists = NULL;
+ static::trimParents($parents, $element_index);
+ $input_values = &NestedArray::getValue($user_input, $parents, $key_exists);
+ if ($key_exists) {
+ $moved_element = array_splice($input_values, $element_index, 1);
+ array_splice($input_values, $element_index + $offset, 0, $moved_element);
+ // Re-index the array to maintain proper keys.
+ $input_values = \array_values($input_values);
+ }
+
+ $form_state->setUserInput($user_input);
+ $form_state->setRebuild();
+ }
+
+ /**
+ * Submit function for array "add one" button.
+ *
+ * @param array $form
+ * Form render array.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ * Form state.
+ */
+ public static function addOne(array &$form, FormStateInterface $form_state) {
+ $button_element = $form_state->getTriggeringElement();
+ $count_property = static::buildCountProperty($button_element['#name']);
+ // Modify stored item count.
+ $item_count = $form_state->get($count_property) ?? 0;
+ $item_count++;
+ $form_state->set($count_property, $item_count);
+ $form_state->setRebuild();
+ }
+
+ /**
+ * Utility function to trim the triggering element's parents array.
+ *
+ * Used to get the correct position in the user input array for modifications.
+ *
+ * @param array $parents
+ * Parents array.
+ * @param int $element_index
+ * Element index.
+ */
+ public static function trimParents(array &$parents, int $element_index): void {
+ for ($i = count($parents) - 1; $i >= 0; $i--) {
+ if ($parents[$i] == $element_index) {
+ $ei_position = $i;
+ break;
+ }
+ }
+ $offset = 0 - (count($parents) - $ei_position);
+ \array_splice($parents, $offset);
}
}
diff --git a/modules/json_form_widget/src/FormBuilder.php b/modules/json_form_widget/src/FormBuilder.php
index 0eef2582f6..38f2771117 100644
--- a/modules/json_form_widget/src/FormBuilder.php
+++ b/modules/json_form_widget/src/FormBuilder.php
@@ -68,7 +68,7 @@ public function __construct(
SchemaRetriever $schema_retriever,
FieldTypeRouter $router,
SchemaUiHandler $schema_ui_handler,
- LoggerInterface $loggerChannel
+ LoggerInterface $loggerChannel,
) {
$this->schemaRetriever = $schema_retriever;
$this->router = $router;
diff --git a/modules/json_form_widget/src/Plugin/Field/FieldWidget/JsonFormWidget.php b/modules/json_form_widget/src/Plugin/Field/FieldWidget/JsonFormWidget.php
index 57a632e976..3c260f3a6f 100644
--- a/modules/json_form_widget/src/Plugin/Field/FieldWidget/JsonFormWidget.php
+++ b/modules/json_form_widget/src/Plugin/Field/FieldWidget/JsonFormWidget.php
@@ -3,14 +3,14 @@
namespace Drupal\json_form_widget\Plugin\Field\FieldWidget;
use Drupal\Core\Entity\FieldableEntityInterface;
+use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\WidgetBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\json_form_widget\FormBuilder;
+use Drupal\json_form_widget\ValueHandler;
use Symfony\Component\DependencyInjection\ContainerInterface;
-use Drupal\Core\Field\FieldDefinitionInterface;
use Symfony\Component\HttpFoundation\RequestStack;
-use Drupal\json_form_widget\ValueHandler;
/**
* Plugin implementation of the 'json_form_widget'.
@@ -82,7 +82,7 @@ public function __construct(
array $third_party_settings,
FormBuilder $builder,
ValueHandler $value_handler,
- RequestStack $request_stack
+ RequestStack $request_stack,
) {
parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $third_party_settings);
$this->builder = $builder;
diff --git a/modules/json_form_widget/src/SchemaUiHandler.php b/modules/json_form_widget/src/SchemaUiHandler.php
index 8d47b9a5eb..b8e67532f6 100644
--- a/modules/json_form_widget/src/SchemaUiHandler.php
+++ b/modules/json_form_widget/src/SchemaUiHandler.php
@@ -66,7 +66,7 @@ public static function create(ContainerInterface $container) {
public function __construct(
SchemaRetriever $schema_retriever,
LoggerInterface $loggerChannel,
- WidgetRouter $widget_router
+ WidgetRouter $widget_router,
) {
$this->schemaRetriever = $schema_retriever;
$this->schemaUi = FALSE;
@@ -199,7 +199,13 @@ public function flattenArrays(mixed $spec, array $element) {
unset($element[$spec->child][$key]);
}
}
- $element[$spec->child][0]['#default_value'] = $default_value;
+
+ if (isset($element[$spec->child][0]['field'])) {
+ $element[$spec->child][0]['field']['#default_value'] = $default_value;
+ }
+ else {
+ $element[$spec->child][0]['#default_value'] = $default_value;
+ }
return $element;
}
@@ -210,6 +216,9 @@ private function formatArrayDefaultValue($item) {
if (!empty($item['#default_value'])) {
return [$item['#default_value'] => $item['#default_value']];
}
+ if (!empty($item['field']['#default_value'])) {
+ return [$item['field']['#default_value'] => $item['field']['#default_value']];
+ }
return [];
}
diff --git a/modules/json_form_widget/src/ValueHandler.php b/modules/json_form_widget/src/ValueHandler.php
index 8902f50533..79f4dfd94a 100644
--- a/modules/json_form_widget/src/ValueHandler.php
+++ b/modules/json_form_widget/src/ValueHandler.php
@@ -148,9 +148,12 @@ public function handleArrayValues($formValues, $property, $schema) {
*/
private function flattenArraysInArrays($value) {
$data = [];
+ if (isset($value['actions'])) {
+ unset($value['actions']);
+ }
if (is_array($value)) {
foreach ($value as $item) {
- $data[] = $this->cleanSelectId($item);
+ $data[] = is_array($item) ? $this->flattenArraysInArrays($item) : $this->cleanSelectId($item);
}
}
elseif (!empty($value)) {
diff --git a/modules/json_form_widget/src/WidgetRouter.php b/modules/json_form_widget/src/WidgetRouter.php
index 79047a42d1..00a0663558 100644
--- a/modules/json_form_widget/src/WidgetRouter.php
+++ b/modules/json_form_widget/src/WidgetRouter.php
@@ -147,6 +147,7 @@ public function handleListElement(mixed $spec, array $element) {
* The dropdown element configured.
*/
public function getDropdownElement(mixed $element, mixed $spec, mixed $titleProperty = FALSE) {
+ ArrayHelper::flattenArrayElementFieldset($element);
$element['#type'] = $this->getSelectType($spec);
$element['#options'] = $this->getDropdownOptions($spec->source, $titleProperty);
if ($element['#type'] === 'select_or_other_select') {
diff --git a/modules/json_form_widget/tests/src/Unit/ArrayHelperTest.php b/modules/json_form_widget/tests/src/Unit/ArrayHelperTest.php
index 7819dc8bd4..2f88b400d8 100644
--- a/modules/json_form_widget/tests/src/Unit/ArrayHelperTest.php
+++ b/modules/json_form_widget/tests/src/Unit/ArrayHelperTest.php
@@ -2,20 +2,20 @@
namespace Drupal\Tests\json_form_widget\Unit;
-use PHPUnit\Framework\TestCase;
-use Drupal\json_form_widget\ArrayHelper;
-use MockChain\Chain;
use Drupal\Component\DependencyInjection\Container;
use Drupal\Core\Form\FormState;
use Drupal\Core\Logger\LoggerChannelFactory;
use Drupal\Core\StringTranslation\TranslationManager;
+use Drupal\json_form_widget\ArrayHelper;
use Drupal\json_form_widget\FieldTypeRouter;
use Drupal\json_form_widget\IntegerHelper;
use Drupal\json_form_widget\ObjectHelper;
use Drupal\json_form_widget\SchemaUiHandler;
use Drupal\json_form_widget\StringHelper;
use Drupal\metastore\SchemaRetriever;
+use MockChain\Chain;
use MockChain\Options;
+use PHPUnit\Framework\TestCase;
/**
* Test class for ArrayHelper.
@@ -79,7 +79,7 @@ public function testComplex() {
$result = $array_helper->handleArrayElement($definition, [], $form_state, $context);
$expected = $this->getExpectedComplexArrayElement();
unset($result['actions']);
- unset($result['distribution'][0]['distribution']['schema']['schema']['fields']['actions']);
+ unset($result['distribution'][0]['distribution']['actions']);
$this->assertEquals($expected, $result);
}
@@ -182,10 +182,10 @@ private function getExpectedObject() {
"#required" => FALSE,
],
],
- ]
+ ],
],
],
- ]
+ ],
],
],
"#required" => FALSE,