Merge pull request #4234 from octobercms/fix/repeater-cleanup

Simplify Repeater Logic. Fixes #4230. Related: https://github.com/rainlab/translate-plugin/pull/466
This commit is contained in:
Luke Towers 2019-04-17 17:15:48 -06:00 committed by GitHub
commit f3f655cc25
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 60 additions and 71 deletions

View File

@ -10,9 +10,6 @@ use October\Rain\Html\Helper as HtmlHelper;
*/
class Repeater extends FormWidgetBase
{
const INDEX_PREFIX = '___index_';
const GROUP_PREFIX = '___group_';
//
// Configurable properties
//
@ -56,11 +53,6 @@ class Repeater extends FormWidgetBase
*/
protected $defaultAlias = 'repeater';
/**
* @var string Form field name for capturing an index.
*/
protected $indexInputName;
/**
* @var int Count of repeated items.
*/
@ -83,13 +75,15 @@ class Repeater extends FormWidgetBase
protected $useGroups = false;
/**
* @var string Form field name for capturing an index.
*/
protected $groupInputName;
protected $groupDefinitions = [];
/**
* Determines if repeater has been initialised previously
*
* @var boolean
*/
protected $loaded = false;
/**
* @inheritDoc
*/
@ -108,14 +102,17 @@ class Repeater extends FormWidgetBase
$this->previewMode = true;
}
// Check for loaded flag in POST
if ((bool) post($this->alias . '_loaded') === true) {
$this->loaded = true;
}
$fieldName = $this->formField->getName(false);
$this->indexInputName = $this->alias.self::INDEX_PREFIX.$fieldName;
$this->groupInputName = $this->alias.self::GROUP_PREFIX.$fieldName;
$this->processGroupMode();
if (!self::$onAddItemCalled) {
$this->processExistingItems();
$this->processItems();
}
}
@ -136,7 +133,7 @@ class Repeater extends FormWidgetBase
// Refresh the loaded data to support being modified by filterFields
// @see https://github.com/octobercms/october/issues/2613
if (!self::$onAddItemCalled) {
$this->processExistingItems();
$this->processItems();
}
if ($this->previewMode) {
@ -145,9 +142,6 @@ class Repeater extends FormWidgetBase
}
}
$this->vars['indexInputName'] = $this->indexInputName;
$this->vars['groupInputName'] = $this->groupInputName;
$this->vars['prompt'] = $this->prompt;
$this->vars['formWidgets'] = $this->formWidgets;
$this->vars['titleFrom'] = $this->titleFrom;
@ -186,15 +180,6 @@ class Repeater extends FormWidgetBase
return $value;
}
if ($this->useGroups) {
foreach ($value as $index => &$data) {
$data['_group'] = $this->getGroupCodeFromIndex($index);
}
// Make sure the $data reference is removed from memory so that the next loop won't modify it
// which would cause the last item to receive the group code of the second-last item
unset($data);
}
if ($this->minItems && count($value) < $this->minItems) {
throw new ApplicationException(Lang::get('backend::lang.repeater.min_items_failed', ['name' => $this->fieldName, 'min' => $this->minItems, 'items' => count($value)]));
}
@ -219,52 +204,52 @@ class Repeater extends FormWidgetBase
}
/**
* Processes existing form data and applies it to the form widgets.
* Processes form data and applies it to the form widgets.
* @return void
*/
protected function processExistingItems()
protected function processItems()
{
$loadedIndexes = $loadedGroups = [];
$loadValue = $this->getLoadValue();
$currentValue = ($this->loaded === true)
? post($this->formField->getName())
: $this->getLoadValue();
if ($currentValue === null) {
$this->indexCount = 0;
$this->formWidgets = [];
return;
}
$groupMap = [];
// Ensure that the minimum number of items are preinitialized
// ONLY DONE WHEN NOT IN GROUP MODE
if (!$this->useGroups && $this->minItems > 0) {
if (!is_array($loadValue)) {
$loadValue = [];
if (!is_array($currentValue)) {
$currentValue = [];
for ($i = 0; $i < $this->minItems; $i++) {
$loadValue[$i] = [];
$currentValue[$i] = [];
}
} elseif (count($loadValue) < $this->minItems) {
for ($i = 0; $i < ($this->minItems - count($loadValue)); $i++) {
$loadValue[] = [];
} elseif (count($currentValue) < $this->minItems) {
for ($i = 0; $i < ($this->minItems - count($currentValue)); $i++) {
$currentValue[] = [];
}
}
}
if (is_array($loadValue)) {
foreach ($loadValue as $index => $loadedValue) {
$loadedIndexes[] = $index;
$loadedGroups[] = array_get($loadedValue, '_group');
if (is_array($currentValue) && count($currentValue)) {
foreach ($currentValue as $value) {
$groupMap[] = array_get($value, '_group');
}
}
$itemIndexes = post($this->indexInputName, $loadedIndexes);
$itemGroups = post($this->groupInputName, $loadedGroups);
if (!count($itemIndexes)) {
if (!count($groupMap)) {
return;
}
$items = array_combine(
(array) $itemIndexes,
(array) ($this->useGroups ? $itemGroups : $itemIndexes)
);
foreach ($items as $itemIndex => $groupCode) {
$this->makeItemFormWidget($itemIndex, $groupCode);
$this->indexCount = max((int) $itemIndex, $this->indexCount);
foreach ($groupMap as $index => $groupCode) {
$this->makeItemFormWidget($index, $groupCode);
}
$this->indexCount = max(count($currentValue), $this->indexCount);
}
/**
@ -281,7 +266,7 @@ class Repeater extends FormWidgetBase
$config = $this->makeConfig($configDefinition);
$config->model = $this->model;
$config->data = $this->getLoadValueFromIndex($index);
$config->data = $this->getValueFromIndex($index);
$config->alias = $this->alias . 'Form'.$index;
$config->arrayName = $this->getFieldName().'['.$index.']';
$config->isNested = true;
@ -300,17 +285,20 @@ class Repeater extends FormWidgetBase
}
/**
* Returns the load data at a given index.
* Returns the data at a given index.
* @param int $index
*/
protected function getLoadValueFromIndex($index)
protected function getValueFromIndex($index)
{
$loadValue = $this->getLoadValue();
if (!is_array($loadValue)) {
$loadValue = [];
$value = ($this->loaded === true)
? post($this->formField->getName())
: $this->getLoadValue();
if (!is_array($value)) {
$value = [];
}
return array_get($loadValue, $index, []);
return array_get($value, $index, []);
}
//
@ -321,8 +309,6 @@ class Repeater extends FormWidgetBase
{
self::$onAddItemCalled = true;
$this->indexCount++;
$groupCode = post('_repeater_group');
$this->prepareVars();
@ -330,7 +316,13 @@ class Repeater extends FormWidgetBase
$this->vars['indexValue'] = $this->indexCount;
$itemContainer = '@#' . $this->getId('items');
return [$itemContainer => $this->makePartial('repeater_item')];
// Increase index count after item is created
++$this->indexCount;
return [
$itemContainer => $this->makePartial('repeater_item')
];
}
public function onRemoveItem()

View File

@ -34,6 +34,8 @@
</a>
<?php endif ?>
</div>
<input type="hidden" name="<?= $this->alias; ?>_loaded" value="1">
<?php endif ?>
<script type="text/template" data-group-palette-template>

View File

@ -45,9 +45,4 @@
<?php endif ?>
</div>
<input type="hidden" name="<?= $indexInputName ?>[]" value="<?= $indexValue ?>" />
<?php if ($useGroups): ?>
<input type="hidden" name="<?= $groupInputName ?>[]" value="<?= $groupCode ?>" />
<?php endif ?>
</li>