public static function save_field_configuration(field_controller $field, \stdClass $formdata) {
        foreach ($formdata as $key => $value) {
            if ($key === 'configdata' && is_array($formdata->configdata)) {
                $field->set($key, json_encode($value));
            } else if ($key === 'id' || ($key === 'type' && $field->get('id'))) {
                continue;
            } else if (field::has_property($key)) {
                $field->set($key, $value);
            }
        }

        $isnewfield = empty($field->get('id'));

        // Process files in description.
        if (isset($formdata->description_editor)) {
            if (!$field->get('id')) {
                // We need 'id' field to store files used in description.
                $field->save();
            }

            $data = (object) ['description_editor' => $formdata->description_editor];
            $textoptions = $field->get_handler()->get_description_text_options();
            $data = file_postupdate_standard_editor($data, 'description', $textoptions, $textoptions['context'],
                'core_customfield', 'description', $field->get('id'));
            $field->set('description', $data->description);
            $field->set('descriptionformat', $data->descriptionformat);
        }

        // Save the field.
        $field->save();

        if ($isnewfield) {
            // Move to the end of the category.
            self::move_field($field, $field->get('categoryid'));
        }

        if ($isnewfield) {
            field_created::create_from_object($field)->trigger();
        } else {
            field_updated::create_from_object($field)->trigger();
        }
    }