diff --git a/src/Fields/Field.php b/src/Fields/Field.php index 634f03adff..e187a11767 100644 --- a/src/Fields/Field.php +++ b/src/Fields/Field.php @@ -297,9 +297,26 @@ public function value() public function defaultValue() { + if ($this->hasComputedDefault()) { + return Fields::resolveDefault(Str::chopStart($this->config['default'], 'computed:')); + } + return $this->config['default'] ?? $this->fieldtype()->defaultValue(); } + public function hasComputedDefault(): bool + { + if (! isset($this->config['default'])) { + return false; + } + + if (! is_string($this->config['default'])) { + return false; + } + + return Str::startsWith($this->config['default'], 'computed:'); + } + public function validationValue() { return $this->fieldtype()->validationValue($this->value); diff --git a/src/Fields/Fields.php b/src/Fields/Fields.php index 054c14361d..60bb1a5226 100644 --- a/src/Fields/Fields.php +++ b/src/Fields/Fields.php @@ -2,6 +2,7 @@ namespace Statamic\Fields; +use Closure; use Facades\Statamic\Fields\FieldRepository; use Facades\Statamic\Fields\Validator; use Illuminate\Support\Collection; @@ -21,6 +22,19 @@ class Fields protected $withValidatableValues = false; protected $withComputedValues = false; + /** @var array */ + protected static array $computedFieldDefaultCallbacks = []; + + public static function default(string $key, Closure $callback): void + { + static::$computedFieldDefaultCallbacks[$key] = $callback; + } + + public static function resolveDefault(string $key): mixed + { + return static::$computedFieldDefaultCallbacks[$key](); + } + public function __construct($items = [], $parent = null, $parentField = null, $parentIndex = null) { $this diff --git a/tests/Fields/FieldTest.php b/tests/Fields/FieldTest.php index fe85243b09..cadb125ac9 100644 --- a/tests/Fields/FieldTest.php +++ b/tests/Fields/FieldTest.php @@ -6,6 +6,7 @@ use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\Attributes\Test; use Statamic\Fields\Field; +use Statamic\Fields\Fields; use Statamic\Fields\Fieldtype; use Statamic\Fields\Value; use Statamic\Forms\Form; @@ -294,6 +295,7 @@ public function converts_to_array_suitable_for_rendering_fields_in_publish_compo ->andReturn(new class extends Fieldtype { protected $component = 'example'; + protected $configFields = [ 'a_config_field_with_pre_processing' => ['type' => 'with_processing'], 'a_config_field_without_pre_processing' => ['type' => 'without_processing'], @@ -474,6 +476,31 @@ public function defaultValue() $this->assertEquals('fieldtype defined default preprocessed', $field->preProcess()->value()); } + #[Test] + public function preprocessing_a_field_with_no_value_and_computed_default_value_will_use_the_computed_function() + { + FieldtypeRepository::shouldReceive('find') + ->with('fieldtype') + ->andReturn(new class extends Fieldtype + { + public function preProcess($data) + { + return $data.' preprocessed'; + } + + public function defaultValue() + { + return 'fieldtype defined default'; + } + }); + + Fields::default('computed-value', fn () => 'computed defined default'); + + $field = (new Field('test', ['default' => 'computed:computed-value', 'type' => 'fieldtype'])); + + $this->assertEquals('computed defined default preprocessed', $field->preProcess()->value()); + } + #[Test] public function converting_to_an_array_will_inline_the_handle() {