Skip to content

Changes made in settings model's beforeSave function are lost immediately afterward #1360

@interworks-morr

Description

@interworks-morr

Winter CMS Build

1.2

PHP Version

8.3

Database engine

MySQL/MariaDB

Plugins installed

No response

Issue description

While testing the upgrade from Winter CMS 1.2.3 to 1.2.7, an automated test began failing because changes to a settings model in its beforeSave function are lost immediately after the beforeSave function returns. I have traced it down to the Winter\Storm\Database\Model::bootNicerEvents function where it fires $model->fireEvent('model.beforeSave').

I added a dump at the end of the beforeSave and the attributes are what I expect. I added a dump just after this event is fired and the attributes are reverted.

After Luke's hint to look at this commit, I changed bindEventOnce to bindEvent in the bootNicerEvents function and it started working as expected, so this commit is the likely cause of the issue. However, the root cause may be something deeper inside of the bindEventOnce function specifically for settings models.

Steps to replicate

  1. Create a settings model with some simple text fields.
    1. Run something like php artisan create:settings Company.Plugin TestSettings
    2. Add the following to the fields.yaml file:
fields:
    foo:
        label: Foo
        type: text
    bar:
        label: Bar
        type: text
  1. Register the backend settings page as needed to point to this new settings model.
            'test'  => [
                'label'       => 'Test Settings',
                'description' => 'Test settings.',
                'icon'        => 'icon-lock',
                'category'    => 'Testing',
                'class'       => 'Company\Plugin\Models\TestSettings',
                'order'       => 30,
                'keywords'    => 'testing',
                'permissions' => ['company.plugin.*'],
            ],
  1. Add a beforeSave function to the settings model and override the value attribute with something noticeable.
    public function beforeSave()
    {
        $value                     = json_decode($this->attributes['value'] ?? '[]', true);
        $value['foo']              = 'nonsense';
        $value['baz']              = 'more nonsense';
        $this->attributes['value'] = json_encode($value);
    }
  1. Open the backend settings page, change the values in the text fields, and click the save button.
  2. Check the system_settings table to verify that it accepted the values on the form and whether it accepted the changes from the beforeSave function.
  3. Modify Winter\Storm\Database\Model::bootNicerEvents to use bindEvent instead of bindEventOnce and repeat steps 4-5 again.

Workaround

It appears that beforeValidate does not exhibit this same behavior, so it can be used instead if needed/possible.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions