User tests: Successful: Unsuccessful:
Pull Request for Issue # .
(ChatGPT helped improving my original PR description to make it more clear)
This PR refactors the MVC FormController class to reduce duplicated logic and improve extensibility.
The current save() method performs many different tasks in a single large block, making it difficult for child controllers to override small parts of the workflow without re-implementing the entire method. This PR introduces several internal helper methods and reorganizes existing logic to make the controller easier to maintain and extend.
Repeated check-in and check-out code in the edit, cancel, and save tasks has been moved into two reusable methods:
attemptCheckin()attemptCheckout()This isolates record-locking behavior and allows child controllers to override it without touching unrelated logic.
The repeated logic for normalizing calendar form fields (applying SERVER_UTC or USER_UTC filters and writing the normalized values back to the request data) has been extracted into:
applyFilterForCalendarFieldsToRequestData()This logic is used both when validation fails during save() and in the reload() task.
save() method into smaller stepsThe original save() method contained many responsibilities (data preprocessing, plugin manipulation, permission checking, validation, saving, messages, redirection, check-in).
The method has now been broken into clearly named helper methods:
preprocessSaveData()
Allows child controllers to adjust raw request data before any validation or permission checks happen.
normalizeRequestData()
Extracted from existing logic. Allows plugins to modify request data before validation.
preSaveHook()
Allows child controllers to modify the already-validated data before it is passed to the model for saving.
handleSaveDataValidationErrorMessages()
Extracted from existing code to output validation errors.
setSaveSuccessMessage()
Extracted from existing code to construct and set success messages after a successful save.
By splitting these steps, child controllers can now override only the parts they need — without copying the entire save() method.
FormController currently type-hints $model as BaseDatabaseModel.
However, some of the logic used by FormController (including check-in/check-out) is available only in:
FormModel, orWhile refactoring, I kept BaseDatabaseModel for consistency with the existing code.
However, the more accurate type hint would be FormModel.
Question:
Should the new helper methods use FormModel as the parameter type?
If desired, I can adjust the PR accordingly.
FormController::save() assumes a database table always existsThe current implementation assumes that every item being edited has an associated Table object.
This is not always true — for example, the OverrideController in com_languages:
OverrideController does not use a database table, so it cannot reuse FormController::save() at all.
Controllers without tables are forced to reimplement the entire save process.
Possible improvement (for a future PR):
FormController::save().This would allow table-less controllers (e.g., for configuration or overrides) to reuse the base controller logic.
Please select:
Documentation link for docs.joomla.org:
No documentation changes for docs.joomla.org needed
Pull Request link for manual.joomla.org:
No documentation changes for manual.joomla.org needed
| Status | New | ⇒ | Pending |
| Category | ⇒ | Libraries |