From 4cfea66c99d4f49436fd20d9d007c6ef545ab44b Mon Sep 17 00:00:00 2001 From: Giuseppe Criscione <18699708+giuscris@users.noreply.github.com> Date: Mon, 16 Feb 2026 20:46:48 +0100 Subject: [PATCH 1/4] Always initialize form fields with current values --- .../src/Panel/Controllers/FilesController.php | 8 ++------ .../src/Panel/Controllers/OptionsController.php | 15 ++++----------- .../src/Panel/Controllers/PagesController.php | 7 ++----- .../src/Panel/Controllers/PluginsController.php | 8 ++------ .../src/Panel/Controllers/UsersController.php | 8 ++------ 5 files changed, 12 insertions(+), 34 deletions(-) diff --git a/formwork/src/Panel/Controllers/FilesController.php b/formwork/src/Panel/Controllers/FilesController.php index b652725ce..8453bc123 100644 --- a/formwork/src/Panel/Controllers/FilesController.php +++ b/formwork/src/Panel/Controllers/FilesController.php @@ -9,7 +9,6 @@ use Formwork\Files\FileFactory; use Formwork\Forms\FormData; use Formwork\Http\JsonResponse; -use Formwork\Http\RequestMethod; use Formwork\Http\Response; use Formwork\Http\ResponseStatus; use Formwork\Images\Image; @@ -145,11 +144,8 @@ public function edit(RouteParams $routeParams): Response return $this->redirectToReferer(base: $this->panel->panelRoot()); } - // Set initial values on GET - if ($this->request->method() === RequestMethod::GET) { - $file->fields()->setValues($file->data()) - ->isValid(); // Pre-validate to populate validation state - } + $file->fields()->setValues($file->data()) + ->isValid(); // Pre-validate to populate validation state $form = $this->form('file-metadata', $file->fields()) ->processRequest($this->request, uploadFiles: false); diff --git a/formwork/src/Panel/Controllers/OptionsController.php b/formwork/src/Panel/Controllers/OptionsController.php index f9c7fb963..c3d346c27 100644 --- a/formwork/src/Panel/Controllers/OptionsController.php +++ b/formwork/src/Panel/Controllers/OptionsController.php @@ -3,7 +3,6 @@ namespace Formwork\Panel\Controllers; use Formwork\Config\Config; -use Formwork\Http\RequestMethod; use Formwork\Http\Response; use Formwork\Parsers\Yaml; use Formwork\Schemes\Schemes; @@ -44,11 +43,8 @@ public function systemOptions(Schemes $schemes): Response $scheme = $schemes->get('config.system'); $fields = $scheme->fields(); - // Set initial values on GET - if ($this->request->method() === RequestMethod::GET) { - $fields->setValues($this->config->get('system')) - ->isValid(); // Pre-validate to populate validation state - } + $fields->setValues($this->config->get('system')) + ->isValid(); // Pre-validate to populate validation state $form = $this->form('system-options', $fields) ->processRequest($this->request); @@ -97,11 +93,8 @@ public function siteOptions(Schemes $schemes): Response $scheme = $schemes->get('config.site'); $fields = $scheme->fields(); - // Set initial values on GET - if ($this->request->method() === RequestMethod::GET) { - $fields->setValues($this->site->data()) - ->isValid(); // Pre-validate to populate validation state - } + $fields->setValues($this->site->data()) + ->isValid(); // Pre-validate to populate validation state $form = $this->form('site-options', $fields) ->processRequest($this->request); diff --git a/formwork/src/Panel/Controllers/PagesController.php b/formwork/src/Panel/Controllers/PagesController.php index dc13cd837..5f9dea072 100644 --- a/formwork/src/Panel/Controllers/PagesController.php +++ b/formwork/src/Panel/Controllers/PagesController.php @@ -9,7 +9,6 @@ use Formwork\Forms\FormData; use Formwork\Http\JsonResponse; use Formwork\Http\RequestData; -use Formwork\Http\RequestMethod; use Formwork\Http\Response; use Formwork\Http\ResponseStatus; use Formwork\Pages\Page; @@ -223,10 +222,8 @@ public function edit(RouteParams $routeParams): Response // Clone the page fields to work with a separate copy $fieldCollection = $page->fields()->deepClone(); - if ($this->request->method() === RequestMethod::GET) { - $fieldCollection->setValues($page->data()) - ->isValid(); // Pre-validate to populate validation state - } + $fieldCollection->setValues($page->data()) + ->isValid(); // Pre-validate to populate validation state $form = $this->form('page-editor', $fieldCollection) ->setDefaultUploadsDestination($page->contentPath()) diff --git a/formwork/src/Panel/Controllers/PluginsController.php b/formwork/src/Panel/Controllers/PluginsController.php index 1f0975626..e5b061963 100644 --- a/formwork/src/Panel/Controllers/PluginsController.php +++ b/formwork/src/Panel/Controllers/PluginsController.php @@ -4,7 +4,6 @@ use Formwork\Fields\FieldCollection; use Formwork\Http\JsonResponse; -use Formwork\Http\RequestMethod; use Formwork\Http\Response; use Formwork\Http\ResponseStatus; use Formwork\Parsers\Yaml; @@ -72,11 +71,8 @@ public function plugin(RouteParams $routeParams, Plugins $plugins): Response $fields = $scheme->fields(); - // Set initial values on GET - if ($this->request->method() === RequestMethod::GET) { - $data = $this->config->get("plugins.{$name}", []); - $fields->setValues($data); - } + $fields->setValues($this->config->get("plugins.{$name}", [])) + ->isValid(); // Pre-validate to populate validation state $form = $this->form('plugin-options', $fields) ->processRequest($this->request); diff --git a/formwork/src/Panel/Controllers/UsersController.php b/formwork/src/Panel/Controllers/UsersController.php index fc27d323f..4a0875ebc 100644 --- a/formwork/src/Panel/Controllers/UsersController.php +++ b/formwork/src/Panel/Controllers/UsersController.php @@ -7,7 +7,6 @@ use Formwork\Fields\Field; use Formwork\Forms\FormData; use Formwork\Http\FileResponse; -use Formwork\Http\RequestMethod; use Formwork\Http\Response; use Formwork\Images\Image; use Formwork\Router\RouteParams; @@ -173,11 +172,8 @@ public function profile(RouteParams $routeParams): Response // Disable role field if it cannot be changed $fields->get('role')->set('disabled', !$this->panel->user()->canChangeRoleOf($user)); - // Set initial values on GET - if ($this->request->method() === RequestMethod::GET) { - $fields->setValues($user) - ->isValid(); // Pre-validate to populate validation state - } + $fields->setValues($user) + ->isValid(); // Pre-validate to populate validation state $form = $this->form('user-profile', $fields) ->processRequest($this->request, uploadFiles: false, preserveEmpty: false); From 5a9297e8e7ef90925909480ef8cb9fb04019072a Mon Sep 17 00:00:00 2001 From: Giuseppe Criscione <18699708+giuscris@users.noreply.github.com> Date: Mon, 16 Feb 2026 20:48:09 +0100 Subject: [PATCH 2/4] Add the possibility to ignore empty values in password fields --- formwork/fields/password.php | 15 +++++++++++++++ panel/views/fields/password.php | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/formwork/fields/password.php b/formwork/fields/password.php index a94e315f4..458e0b9e8 100644 --- a/formwork/fields/password.php +++ b/formwork/fields/password.php @@ -1,9 +1,24 @@ 'text', + + 'methods' => [ + 'ignoreEmpty' => function (Field $field) { + return $field->is('ignoreEmpty', false); + }, + + 'setValue' => function (Field $field, $value) { + if ($field->ignoreEmpty() && Constraint::isEmpty($value)) { + return $field->value(); + } + return $value; + }, + ], ]; }; diff --git a/panel/views/fields/password.php b/panel/views/fields/password.php index 5abd5fd17..1fbf679d7 100644 --- a/panel/views/fields/password.php +++ b/panel/views/fields/password.php @@ -12,7 +12,7 @@ 'maxlength' => $field->maxLength(), 'pattern' => $field->pattern(), 'autocomplete' => $field->autocomplete(), - 'required' => $field->isRequired(), + 'required' => $field->isRequired() && !$field->ignoreEmpty(), 'disabled' => $field->isDisabled(), 'hidden' => $field->isHidden(), ]) ?>> From c0f2d11f207b9bf976f261cf488b8d2a319f9a2a Mon Sep 17 00:00:00 2001 From: Giuseppe Criscione <18699708+giuscris@users.noreply.github.com> Date: Mon, 16 Feb 2026 20:55:20 +0100 Subject: [PATCH 3/4] Update `$password->ignoreEmpty()` documentation --- formwork/fields/password.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/formwork/fields/password.php b/formwork/fields/password.php index 458e0b9e8..50a7c5479 100644 --- a/formwork/fields/password.php +++ b/formwork/fields/password.php @@ -9,7 +9,12 @@ 'extend' => 'text', 'methods' => [ - 'ignoreEmpty' => function (Field $field) { + /** + * Return whether to ignore empty values when setting the field value + * + * This is useful for password fields, where you don't want to overwrite the existing password with an empty value if the user doesn't enter a new password. + */ + 'ignoreEmpty' => function (Field $field): bool { return $field->is('ignoreEmpty', false); }, From d3087db192ca1d047a4ff5e361ff2646c4e0dbac Mon Sep 17 00:00:00 2001 From: Giuseppe Criscione <18699708+giuscris@users.noreply.github.com> Date: Mon, 16 Feb 2026 21:50:48 +0100 Subject: [PATCH 4/4] Remove unconditional pre-validation --- formwork/src/Panel/Controllers/FilesController.php | 3 +-- formwork/src/Panel/Controllers/OptionsController.php | 6 ++---- formwork/src/Panel/Controllers/PagesController.php | 3 +-- formwork/src/Panel/Controllers/PluginsController.php | 3 +-- formwork/src/Panel/Controllers/UsersController.php | 3 +-- 5 files changed, 6 insertions(+), 12 deletions(-) diff --git a/formwork/src/Panel/Controllers/FilesController.php b/formwork/src/Panel/Controllers/FilesController.php index 8453bc123..2539142f6 100644 --- a/formwork/src/Panel/Controllers/FilesController.php +++ b/formwork/src/Panel/Controllers/FilesController.php @@ -144,8 +144,7 @@ public function edit(RouteParams $routeParams): Response return $this->redirectToReferer(base: $this->panel->panelRoot()); } - $file->fields()->setValues($file->data()) - ->isValid(); // Pre-validate to populate validation state + $file->fields()->setValues($file->data()); $form = $this->form('file-metadata', $file->fields()) ->processRequest($this->request, uploadFiles: false); diff --git a/formwork/src/Panel/Controllers/OptionsController.php b/formwork/src/Panel/Controllers/OptionsController.php index c3d346c27..2fb1d01b5 100644 --- a/formwork/src/Panel/Controllers/OptionsController.php +++ b/formwork/src/Panel/Controllers/OptionsController.php @@ -43,8 +43,7 @@ public function systemOptions(Schemes $schemes): Response $scheme = $schemes->get('config.system'); $fields = $scheme->fields(); - $fields->setValues($this->config->get('system')) - ->isValid(); // Pre-validate to populate validation state + $fields->setValues($this->config->get('system')); $form = $this->form('system-options', $fields) ->processRequest($this->request); @@ -93,8 +92,7 @@ public function siteOptions(Schemes $schemes): Response $scheme = $schemes->get('config.site'); $fields = $scheme->fields(); - $fields->setValues($this->site->data()) - ->isValid(); // Pre-validate to populate validation state + $fields->setValues($this->site->data()); $form = $this->form('site-options', $fields) ->processRequest($this->request); diff --git a/formwork/src/Panel/Controllers/PagesController.php b/formwork/src/Panel/Controllers/PagesController.php index 5f9dea072..6d0a464ba 100644 --- a/formwork/src/Panel/Controllers/PagesController.php +++ b/formwork/src/Panel/Controllers/PagesController.php @@ -222,8 +222,7 @@ public function edit(RouteParams $routeParams): Response // Clone the page fields to work with a separate copy $fieldCollection = $page->fields()->deepClone(); - $fieldCollection->setValues($page->data()) - ->isValid(); // Pre-validate to populate validation state + $fieldCollection->setValues($page->data()); $form = $this->form('page-editor', $fieldCollection) ->setDefaultUploadsDestination($page->contentPath()) diff --git a/formwork/src/Panel/Controllers/PluginsController.php b/formwork/src/Panel/Controllers/PluginsController.php index e5b061963..76fc937b7 100644 --- a/formwork/src/Panel/Controllers/PluginsController.php +++ b/formwork/src/Panel/Controllers/PluginsController.php @@ -71,8 +71,7 @@ public function plugin(RouteParams $routeParams, Plugins $plugins): Response $fields = $scheme->fields(); - $fields->setValues($this->config->get("plugins.{$name}", [])) - ->isValid(); // Pre-validate to populate validation state + $fields->setValues($this->config->get("plugins.{$name}", [])); $form = $this->form('plugin-options', $fields) ->processRequest($this->request); diff --git a/formwork/src/Panel/Controllers/UsersController.php b/formwork/src/Panel/Controllers/UsersController.php index 4a0875ebc..19194aca3 100644 --- a/formwork/src/Panel/Controllers/UsersController.php +++ b/formwork/src/Panel/Controllers/UsersController.php @@ -172,8 +172,7 @@ public function profile(RouteParams $routeParams): Response // Disable role field if it cannot be changed $fields->get('role')->set('disabled', !$this->panel->user()->canChangeRoleOf($user)); - $fields->setValues($user) - ->isValid(); // Pre-validate to populate validation state + $fields->setValues($user); $form = $this->form('user-profile', $fields) ->processRequest($this->request, uploadFiles: false, preserveEmpty: false);