Skip to content

Commit

Permalink
FIX: Readonly transformation of lazy-loaded searchable dropdown (#11297)
Browse files Browse the repository at this point in the history
Co-authored-by: johannes.hammersen <[email protected]>
  • Loading branch information
johannesx75 and johannes.hammersen authored Jul 25, 2024
1 parent 8a576f9 commit fb7b173
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 0 deletions.
14 changes: 14 additions & 0 deletions src/Forms/SearchableDropdownTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -586,4 +586,18 @@ private function updateOptionsForSchema(
}
return $options;
}

public function performReadonlyTransformation()
{
// This is calling a non-static method statically
// using call_user_func() here to prevent an IDE warning
// The reason we're calling FormField::castedCopy directly is to prevent an ancestor
// call to $this->getSource() which will load the entire DataList into memory which
// causes issues with very large datasets and isn't needed when the field is read-only
$field = call_user_func('SilverStripe\\Forms\\FormField::castedCopy', SearchableLookupField::class);
$field->setSource($this->sourceList);
$field->setReadonly(true);

return $field;
}
}
50 changes: 50 additions & 0 deletions src/Forms/SearchableLookupField.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

namespace SilverStripe\Forms;

use SilverStripe\Core\Convert;
use SilverStripe\ORM\ArrayLib;
use SilverStripe\ORM\DataObjectInterface;
use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\DataList;

/**
* Read-only complement of {@link SearchableDropdownField} and {@link SearchableMultiDropdownField}.
*
* Shows the "human value" of the SearchableDropdownField for the currently selected
* values.
*/
class SearchableLookupField extends LookupField
{
private ?DataList $sourceList = null;

/**
* To retain compatibility with ancestor getSource() this returns an array of only the selected values
*/
public function getSource(): array
{
$values = $this->getValueArray();
if (empty($values) || $this->sourceList === null) {
$selectedValuesList = ArrayList::create();
} else {
$selectedValuesList = $this->sourceList->filterAny(['ID' => $values]);
}
return $this->getListMap($selectedValuesList);
}

/**
* @param mixed $source
*/
public function setSource($source): static
{
// Setting to $this->sourceList instead of $this->source because SelectField.source
// docblock type is array|ArrayAccess i.e. does not allow DataList
if ($source instanceof DataList) {
$this->sourceList = $source;
} else {
$this->sourceList = null;
}
return $this;
}
}

0 comments on commit fb7b173

Please sign in to comment.