diff --git a/src/Forms/SearchableDropdownField.php b/src/Forms/SearchableDropdownField.php index 901a88739ec..98548810d52 100644 --- a/src/Forms/SearchableDropdownField.php +++ b/src/Forms/SearchableDropdownField.php @@ -9,7 +9,7 @@ class SearchableDropdownField extends DropdownField { use SearchableDropdownTrait; - + // This needs to be defined on the class, not the trait, otherwise there is a PHP error protected $schemaComponent = 'SearchableDropdownField'; diff --git a/src/Forms/SearchableDropdownTrait.php b/src/Forms/SearchableDropdownTrait.php index 5931912f9d2..7d93f04c1eb 100644 --- a/src/Forms/SearchableDropdownTrait.php +++ b/src/Forms/SearchableDropdownTrait.php @@ -265,6 +265,13 @@ public function getSource(): array return $this->getListMap($this->sourceList); } + public function Field($properties = []) + { + $context = $this; + $this->extend('onBeforeRender', $context, $properties); + return $context->customise($properties)->renderWith($context->getTemplates()); + } + /* * @param mixed $source */ @@ -450,9 +457,16 @@ public function getSchemaDataDefaults(): array public function getSchemaStateDefaults(): array { - $data = parent::getSchemaStateDefaults(); - $data = $this->updateDataForSchema($data); - return $data; + $state = [ + 'name' => $this->getName(), + 'id' => $this->ID(), + 'value' => $this->getDefaultSchemaValue(), + 'message' => $this->getSchemaMessage(), + 'data' => [], + ]; + + $state = $this->updateDataForSchema($state); + return $state; } /** @@ -467,6 +481,14 @@ protected function setIsMultiple(bool $isMultiple): static return $this; } + private function getDefaultSchemaValue() + { + if (!$this->getIsLazyLoaded() && $this->hasMethod('getDefaultValue')) { + return $this->getDefaultValue(); + } + return $this->Value(); + } + private function getOptionsForSearchRequest(string $term): array { if (!$this->sourceList) { diff --git a/tests/php/Forms/SearchableDropdownTraitTest.php b/tests/php/Forms/SearchableDropdownTraitTest.php index d6f3aae4cd4..7f4858c81a8 100644 --- a/tests/php/Forms/SearchableDropdownTraitTest.php +++ b/tests/php/Forms/SearchableDropdownTraitTest.php @@ -3,6 +3,7 @@ namespace SilverStripe\Forms\Tests; use SilverStripe\Control\HTTPRequest; +use SilverStripe\Core\ClassInfo; use SilverStripe\Dev\SapphireTest; use SilverStripe\Forms\FieldList; use SilverStripe\Forms\SearchableDropdownField; @@ -217,4 +218,47 @@ public function testGetSchemaDataDefaults(): void $this->assertSame('My placeholder', $schema['placeholder']); $this->assertFalse($schema['searchable']); } + + public function provideLazyLoadedDoesntCallGetSource() + { + $methodsToCall = [ + 'Field', + 'getSchemaStateDefaults', + 'getSchemaState', + 'getSchemaDataDefaults', + 'getSchemaData', + ]; + $classes = [ + SearchableMultiDropdownField::class, + SearchableDropdownField::class, + ]; + $scenarios = []; + foreach ($classes as $class) { + foreach ($methodsToCall as $method) { + $scenarios[] = [ + 'fieldClass' => $class, + 'methodToCall' => $method, + ]; + } + } + return $scenarios; + } + + /** + * @dataProvider provideLazyLoadedDoesntCallGetSource + */ + public function testLazyLoadedDoesntCallGetSource(string $fieldClass, string $methodToCall) + { + // Some methods aren't shared between the two form fields. + if (!ClassInfo::hasMethod($fieldClass, $methodToCall)) { + $this->markTestSkipped("$fieldClass doesn't have method $methodToCall - skipping"); + } + // We have to disable the constructor because it ends up calling a static method, and we can't call static methods on mocks. + $mockField = $this->getMockBuilder($fieldClass)->onlyMethods(['getSource'])->disableOriginalConstructor()->getMock(); + $mockField->expects($this->never())->method('getSource'); + $mockField->setIsLazyLoaded(true); + $mockField->setSource(Team::get()); + $mockField->setForm(new Form()); + $mockField->$methodToCall(); + } }