-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
Subforms: Implementing per-field filters and validation. #14189
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Subforms: Implementing per-field filters and validation. #14189
Conversation
|
@Harmageddon with the last 3 commit i have just fixed a error from drone and minimal cs ;) |
|
@zero-24 Awesome, thank you! Didn't know about this macro, very useful! |
…subform_filter_validation
|
Added some small code cleanups, inspired by @matrikular. Thank you! |
|
Nice pr. Can you please fix the merge conflicts that we can test it? |
|
@laoneo Thank you! It should work now. |
| /** | ||
| * Loads the form instance for the subform. | ||
| * | ||
| * @return JForm The form instance. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you use the namespaced class? Thanks.
|
|
||
| // Prepare the form template | ||
| $formname = 'subform.' . ($this->group ? $this->group . '.' : '') . $this->fieldname; | ||
| $tmpl = JForm::getInstance($formname, $this->formsource, array('control' => $control)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you use the namespaced class? Thanks.
| /** | ||
| * Binds given data to the subform and its elements. | ||
| * | ||
| * @param JForm &$subForm Form instance of the subform. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you use the namespaced class? Thanks.
| * | ||
| * @since __DEPLOY_VERSION__ | ||
| */ | ||
| private function loadSubFormData(&$subForm) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you type hint it?
| for ($i = 0; $i < $c; $i++) | ||
| { | ||
| $control = $this->name . '[' . $this->fieldname . $i . ']'; | ||
| $itemForm = JForm::getInstance($subForm->getName() . $i, $this->formsource, array('control' => $control)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you use the namespaced class? Thanks.
| * | ||
| * @since __DEPLOY_VERSION__ | ||
| */ | ||
| class JFormRuleSubform extends JFormRule |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you use the namespaced class? Thanks.
| * | ||
| * @since __DEPLOY_VERSION__ | ||
| */ | ||
| public function test(SimpleXMLElement $element, $value, $group = null, Registry $input = null, JForm $form = null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you use the namespaced class? Thanks.
| * For example if the field has name="foo" and the group value is set to "bar" then the | ||
| * full field name would end up being "bar[foo]". | ||
| * @param Registry $input An optional Registry object with the entire data set to validate against the entire form. | ||
| * @param JForm $form The form object for which the field is being tested. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you use the namespaced class? Thanks.
|
Thanks, added a few comments to use the namespaced classes. If done I will test it. |
|
Done. Thanks in advance! |
|
Now you got me wrong, use the real classes like \Joomla\CMS\Form\Form, etc. Not just adding a backslash before them. |
|
Oh, sorry. Should I copy the rule to libraries/src/Form/Rule, too, then? Or does it work with this "mixed" form (the subform field and the rule in libraries/joomla/form and the form and the JFormFieldRule class in libraries/src/Form)? |
|
Yes please copy the rule also to |
|
Okay, a little bit confusing. I hope I haven't messed up anything. |
| @@ -0,0 +1,88 @@ | |||
| <?php | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one can be deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The <?php tag? Why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant the whole file as you have the namespaced one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see. Seems I have missed that the rules have been moved completely.
| * @license GNU General Public License version 2 or later; see LICENSE | ||
| */ | ||
|
|
||
| use Joomla\CMS\Form\Form; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor cosmetics here, it belongs below the defined check.
|
I have tested this item ✅ successfully on d379667 After that I created a checkbox field and tried to create an option where the value is not a hex number. It failed. The I changed This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/14189. |
|
I have tested this item ✅ successfully on 6b79cea This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/14189. |
|
@laoneo can you please retest? |
|
Ready to Commit after two successful tests. |
|
Perhaps you should consider to make your own callback for filter instead of hardcoding the subform filter into the form class. More details can be found here #20569 (comment). |
|
Are there any other filters that could serve as an example? I assume that I'd have to create a new class? Where should this class be located? As far as I see, most core rules (like "access") are directly in the Form class. I would use the method you suggest only for third-party extensions and keep the core filters in one place - either in the Form class as of now or each one in a dedicated class. If we keep some filters in one and others in another place, we risk inconsistencies (i.e. if the filter mechanism gets changed) and people will have a harder time to find all available filters when digging through the code. Personally, I'd support your approach to create classes for filters, because I remember debugging the filter method until I found the hardcoded filters in the Form class. But I'd prefer to either move all or none. |
|
What is hardcoded into the Form class' |
|
Okay... So is there any best practice where else to put such a filter? And if I see this right, we'd then require users/developers to use a |
|
IMO, form field filtering and validation should be implicit whenever possible to reduce XML form maintenance needs. So Here's a mockup based on your code and #12414 SharkyKZ@fa514ae. |
Not necessarily, because each part of the API has a separate concern.
|
|
That's the way it is now but is it really correct?
Form fields also provide the data options and data type. So filtering and validation makes sense here. Filtering and validation is applied per-field anyways. That said, shouldn't List-based fields should be validated against options (except when custom option is allowed), numeric fields should be filtered accordingly and Subform should not accept other filters but its own (currently, adding a filter like I think this functionality is vital and should be implemented one way or another. |
|
Rewrite the entire form package from scratch then? There is already a separation of concern regarding each of the object types in the package and an established pattern of use, if you feel this is inefficient feel free to propose a new package but the existing class chain can't just be changed out of the blue like this. By design, filtering and validation are not the responsibility of the |
|
@mbabker Is this something for 3.9? |
|
So with this PR being marked as RTC for almost 4 months now, I'd like to ask what is the status for this one? Is it going to be merged for some future release in the current state or do you prefer me to move the filter to some different location for architectural reasons? |
|
I'm hesitant to merge this because I don't think it is architecturally done correctly and inherently once it ships changing the API will never happen. |
|
I see. However, the problem with moving this method outside the |
|
(sorry, I accidentally hit the wrong button) This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/14189. |
|
Please see #12414. That might have an impact on this PR. |
|
Thank you for your work there! It does indeed have an impact. I'm going to rewrite this PR for 4.0 then. And as this PR here probably won't be ever merged into 3.x after being RTC for 8 months, I'm now closing it and hope for better luck and API integration for 4.0. |
|
Just for the record I'd definitely be interested in seeing this for Joomla 4! |
|
Apparently, the changes proposed in this PR have been added in b06019e and d34a3ec, so I assume they're going to be merged into 4.0, too, and there is no need for a further PR? |
|
Correct. All 3.x changes are merged up to 4.0 before the final release. |
This pull request introduces the option to both filter and validate subforms field by field. The intention is that every single field inside a subform can have its own filter and validation parameters. Before this PR, these parameters would just be ignored.
Summary of Changes
filter="subform"to filter a subform field by filtering its child fields individually.validate="subform"to validate a subform field by validating its child fields individually.getInputmethod into two separate methods to avoid repeated code, because the subform has to be loaded for filtering and validation, too. This change should not change any present behavior of subform fields, because I only moved the existing code into two additional methods.Testing Instructions
filter="subform"to the subform field.filter="int"to a field inside the subform XML and try to save values like "abc" (should be filtered to 0) or "0002" (should be filtered to 2).validate="subform"to the subform field.validate="email"to a field inside the subform XML and try to save values like "foo".multiple="true",multiple="false"and without themultipleparameter for the subform field.Expected result
If a validation fails, there are three options what to display as an error message:
I used option 2, with a fallback to 1. For a subform containing invalid values, only one warning message will be returned, containing the title of the first field with an invalid value. I'm preferring this over option 1, because it is more specific about where the error is. Option 3 would be possible using additional messages, but as the basic implementation of validation itself displays a maximum of 3 messages, I thought it would be sufficient to send only one here.
Documentation Changes Required
As I have no experience in the version numbering of the CMS libraries, I'd be thankful if someone could tell me which value should be added for the@sincetag for theJFormRuleSubformclass.