Skip to content

Commit

Permalink
Cleanup, select2 improvements, required
Browse files Browse the repository at this point in the history
  • Loading branch information
dafeder committed Dec 2, 2024
1 parent 0e301e2 commit 5f7c701
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 135 deletions.
237 changes: 109 additions & 128 deletions modules/json_form_widget/src/ArrayHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,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.
Expand All @@ -65,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.
Expand Down Expand Up @@ -107,7 +107,7 @@ public function handleArrayElement(array $definition, ?array $data, FormStateInt
$items = [];
for ($i = 0; $i < $item_count; $i++) {
$property_required = $is_required && ($i < $min_items);
$items[] = $this->buildArrayElement($definition, $data[$i] ?? NULL, $form_state, array_merge($context, [$i]), $property_required);
$items[] = $this->buildArrayItemElement($definition, $data[$i] ?? NULL, $form_state, array_merge($context, [$i]), $property_required);
}

// Build field element.
Expand All @@ -119,6 +119,7 @@ public function handleArrayElement(array $definition, ?array $data, FormStateInt
'#prefix' => '<div id="' . self::buildWrapperIdentifier($context_name) . '">',
'#suffix' => '</div>',
'#tree' => TRUE,
'#required' => $is_required,
'actions' => [
'#type' => 'actions',
'actions' => [
Expand All @@ -130,6 +131,90 @@ public function handleArrayElement(array $definition, ?array $data, FormStateInt
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)),
];
}

/**
* 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;
}

/**
* Get the form items count for the given field.
*
Expand Down Expand Up @@ -200,19 +285,6 @@ public static function buildCountProperty(string $context_name): array {
return ['json_form_widget_info', $context_name, 'count'];
}

/**
* Build count property.
*
* @param string $context_name
* Field element context name.
*
* @return string[]
* Full count property array.
*/
public static function buildAlterProperty(string $context_name): array {
return ['json_form_widget_info', $context_name, 'alter'];
}

/**
* Helper function to build an action button.
*
Expand All @@ -232,7 +304,7 @@ protected function buildAction(string $title, string $method, string $parent, st
'#value' => $title,
'#submit' => [self::class . '::' . $method],
'#ajax' => [
'callback' => [$this, 'addOrRemoveButtonCallback'],
'callback' => [$this, 'arrayActionButtonCallback'],
'wrapper' => self::buildWrapperIdentifier($parent),
],
'#attributes' => [
Expand Down Expand Up @@ -263,90 +335,6 @@ protected function buildElementActions(string $parent, string $context_name) {
];
}

/**
* 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 buildArrayElement(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' => 'container',
'#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)),
];
}

/**
* 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;
}

/**
* Submit function for element "remove" button.
*
Expand Down Expand Up @@ -383,27 +371,6 @@ public static function remove(array &$form, FormStateInterface $form_state) {
$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);
}

/**
* Submit function for element "move up" button.
*
Expand Down Expand Up @@ -468,18 +435,32 @@ protected static function moveElement(FormStateInterface $form_state, int $offse
*/
public static function addOne(array &$form, FormStateInterface $form_state) {
$button_element = $form_state->getTriggeringElement();
$alter_property = self::buildAlterProperty($button_element['#name']);
$items_alter_index = $form_state->get($alter_property) ?? [];
$items_alter_index[] = count($items_alter_index);

$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->set($alter_property, $items_alter_index);
$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);
}
}
2 changes: 1 addition & 1 deletion modules/json_form_widget/src/ValueHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ private function flattenArraysInArrays($value) {
}
if (is_array($value)) {
foreach ($value as $item) {
$data[] = $this->flattenArraysInArrays($item);
$data[] = is_array($item) ? $this->flattenArraysInArrays($item) : $this->cleanSelectId($item);
}
}
elseif (!empty($value)) {
Expand Down
5 changes: 5 additions & 0 deletions modules/json_form_widget/src/WidgetRouter.php
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,11 @@ public function handleListElement(mixed $spec, array $element) {
* The dropdown element configured.
*/
public function getDropdownElement(mixed $element, mixed $spec, mixed $titleProperty = FALSE) {
// Array elements may be fieldsets, since by default they are simple array
// elements with Remove/Up/Down buttons.
if (isset($element['field']) && $element['#type'] == 'fieldset') {
$element = ['#required' => ($element['#required'] ?? FALSE)] + $element['field'];
}
$element['#type'] = $this->getSelectType($spec);
$element['#options'] = $this->getDropdownOptions($spec->source, $titleProperty);
if ($element['#type'] === 'select_or_other_select') {
Expand Down
12 changes: 6 additions & 6 deletions modules/json_form_widget/tests/src/Unit/ArrayHelperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -182,10 +182,10 @@ private function getExpectedObject() {
"#required" => FALSE,
],
],
]
],
],
],
]
],
],
],
"#required" => FALSE,
Expand Down

0 comments on commit 5f7c701

Please sign in to comment.