? ? Success

User tests: Successful: Unsuccessful:

avatar Harmageddon
Harmageddon
22 Feb 2017

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

  • Introduced a Parameter filter="subform" to filter a subform field by filtering its child fields individually.
  • Introduced a Parameter validate="subform" to validate a subform field by validating its child fields individually.
  • Moved the loading of the JForm instance and its data inside the subform field from the getInput method 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

  • Test with a form containing a subform field.
    • I created a small module for testing purposes on mod_demovalidation. It has no frontend, only the form in the module configuration in backend. Feel free to use this, but I'd recommend that you play around with different parameter combinations to not just replicate my tests.
    • You can also use the testing instructions from #7829 and add some filters and validations...
    • ... or those from #12813, where an inline subform is used.
    • If you are developing an extension using subforms, this is the perfect opportunity to improve it! ;-)
  • Test the impact of filters.
    • Add filter="subform" to the subform field.
    • For example, add 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).
    • Make sure that correct values are not filtered and everything is stored correctly.
  • Test the impact of validation.
    • Add validate="subform" to the subform field.
    • For example, add validate="email" to a field inside the subform XML and try to save values like "foo".
    • Make sure that correct values are not marked as invalid and everything is stored correctly.
  • Make sure that the subform field behaves like before (apart from the added filtering and validation options).
  • Test everything with multiple="true", multiple="false" and without the multiple parameter for the subform field.

Expected result

  • Unfiltered values should be filtered, depending on the filters of the fields inside the subform XML.
  • Invalid values should be rejected, depending on the validation rules of the fields inside the subform XML.

If a validation fails, there are three options what to display as an error message:

  1. "Invalid Field: Subform" (Title of the subform field containing at least one invalid value)
  2. "Invalid Field: Mail" (Title of the first invalid single field inside the subform)
  3. Like 2., but for all invalid fields.

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 @since tag for the JFormRuleSubform class.
  • When the pull request is merged and released, I will add short documentation about the additional parameters on docs.joomla.org.
avatar Harmageddon Harmageddon - open - 22 Feb 2017
avatar Harmageddon Harmageddon - change - 22 Feb 2017
Status New Pending
avatar joomla-cms-bot joomla-cms-bot - change - 22 Feb 2017
Category Libraries
avatar Harmageddon Harmageddon - change - 22 Feb 2017
The description was changed
avatar Harmageddon Harmageddon - edited - 22 Feb 2017
avatar zero-24 zero-24 - change - 22 Feb 2017
Labels Added: ?
avatar zero-24
zero-24 - comment - 22 Feb 2017

@Harmageddon with the last 3 commit i have just fixed a error from drone and minimal cs ;)

avatar Harmageddon
Harmageddon - comment - 22 Feb 2017

@zero-24 Awesome, thank you! Didn't know about this macro, very useful!

avatar Harmageddon
Harmageddon - comment - 22 Feb 2017

Added some small code cleanups, inspired by @matrikular. Thank you!

avatar Harmageddon Harmageddon - edited - 22 Feb 2017
avatar laoneo
laoneo - comment - 5 Sep 2017

Nice pr. Can you please fix the merge conflicts that we can test it?

avatar Harmageddon
Harmageddon - comment - 5 Sep 2017

@laoneo Thank you! It should work now.

avatar laoneo
laoneo - comment - 6 Sep 2017

Thanks, added a few comments to use the namespaced classes. If done I will test it.

avatar Harmageddon
Harmageddon - comment - 6 Sep 2017

Done. Thanks in advance!

avatar laoneo
laoneo - comment - 6 Sep 2017

Now you got me wrong, use the real classes like \Joomla\CMS\Form\Form, etc. Not just adding a backslash before them.

avatar Harmageddon
Harmageddon - comment - 6 Sep 2017

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)?

avatar laoneo
laoneo - comment - 6 Sep 2017

Yes please copy the rule also to libraries/src/Form/Rule. The field has to stay because of autoloading. In Joomla 4 we have moved it also to libraries/src/Form/Field.

avatar Harmageddon
Harmageddon - comment - 6 Sep 2017

Okay, a little bit confusing. I hope I haven't messed up anything.

avatar laoneo laoneo - test_item - 6 Sep 2017 - Tested successfully
avatar laoneo
laoneo - comment - 6 Sep 2017

I have tested this item successfully on d379667

It worked. I'v tested it by changing the file plugins/fields/checkboxes/params/checkboxes.xml to

<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="fieldparams">
		<fieldset name="fieldparams">
			<field
				name="options"
				type="subform"
				label="PLG_FIELDS_CHECKBOXES_PARAMS_OPTIONS_LABEL"
				description="PLG_FIELDS_CHECKBOXES_PARAMS_OPTIONS_DESC"
				layout="joomla.form.field.subform.repeatable-table"
				icon="list"
				multiple="true"
				filter="subform"
				validate="subform"
			>
				<form hidden="true" name="list_templates_modal" repeat="true">
					<field
						name="name"
						type="text"
						label="PLG_FIELDS_CHECKBOXES_PARAMS_OPTIONS_NAME_LABEL"
						size="30"
					/>

					<field
						name="value"
						type="text"
						label="PLG_FIELDS_CHECKBOXES_PARAMS_OPTIONS_VALUE_LABEL"
						size="30"
						validate="color"
					/>
				</form>
			</field>
		</fieldset>
	</fields>
</form>

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 validate="color"to filter="int" and tried to save again, then it successfully saved it but turned the value into an integer.


This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/14189.

avatar SharkyKZ SharkyKZ - test_item - 15 May 2018 - Tested successfully
avatar SharkyKZ
SharkyKZ - comment - 15 May 2018

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.

avatar franz-wohlkoenig
franz-wohlkoenig - comment - 15 May 2018

@laoneo can you please retest?

avatar laoneo
laoneo - comment - 24 May 2018

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.

avatar laoneo laoneo - test_item - 24 May 2018 - Tested successfully
avatar franz-wohlkoenig franz-wohlkoenig - change - 24 May 2018
Status Pending Ready to Commit
avatar laoneo
laoneo - comment - 24 May 2018

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).

avatar Harmageddon
Harmageddon - comment - 24 May 2018

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.

avatar mbabker
mbabker - comment - 24 May 2018

What is hardcoded into the Form class' filterField method is really a bunch of special cases specific to the form data that don't belong to the InputFilter class. So, "core filters" don't need to be hardcoded into the Form class itself unless there is a strong reason why it must be part of the Form API and available at all times.

avatar Harmageddon
Harmageddon - comment - 24 May 2018

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 filter="SomeHelperClass:subform" instead of just filter="subform"?

avatar SharkyKZ
SharkyKZ - comment - 24 May 2018

IMO, form field filtering and validation should be implicit whenever possible to reduce XML form maintenance needs.

So Form's validateField and filterField logic could be moved to FormField. Subform field could then override parent methods and other fields could declare default filters and validation rules to be used when none is added in XML.

Here's a mockup based on your code and #12414 SharkyKZ/joomla-cms@fa514ae.

avatar mbabker
mbabker - comment - 24 May 2018

So Form's validateField and filterField logic could be moved to FormField. Subform field could then override parent methods and other fields could declare default filters and validation rules to be used when none is added in XML.

Not necessarily, because each part of the API has a separate concern.

FormField is in essence the visual representation of the field and handles the rendering, the class chain does not belong in the filtering/validation process at all.

FormRule defines some validation rules to be applied when validating the form's data, these are called during the validation process only.

Form is the data manager for a form instance and this is where the filtering and validation processes belong.

avatar SharkyKZ
SharkyKZ - comment - 25 May 2018

That's the way it is now but is it really correct?

FormField is in essence the visual representation of the field and handles the rendering, the class chain does not belong in the filtering/validation process at all.

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 FormRule be FormFieldRule in the first place?

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 string to subform field causes fatal error).

I think this functionality is vital and should be implemented one way or another.

avatar mbabker
mbabker - comment - 25 May 2018

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 FormField classes and refactoring to move responsibilities like this is no small thing. At the end of the day though, regardless of the class structure, what is responsible for rendering should be a different aspect of the API than what is responsible for data validation (if you look at any proper framework you'll find they have a standalone validation component that the form data is pushed through whereas the closest thing we have to that is the FormRule class and that is tightly coupled to the Form class) and if we're going to start talking refactoring the form API then I don't think we should be making one sort of "super" object that does all the things.

avatar roland-d
roland-d - comment - 22 Jul 2018

@mbabker Is this something for 3.9?

avatar Harmageddon
Harmageddon - comment - 14 Sep 2018

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?
@mbabker @wilsonge (pinging you as the release leads for 3.9/3.10)

avatar mbabker
mbabker - comment - 14 Sep 2018

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.

avatar Harmageddon
Harmageddon - comment - 14 Sep 2018

I see. However, the problem with moving this method outside the Form class is, that we need the form field ($element) in order to load the subform and get the filters for the respective fields inside the subform. Callback filters as well as the InputFilter->clean function only get the value of the field as an argument, but not the whole field.
So a callback filter would get an array containing the values of the fields inside the subform without knowing which value to treat with which filter.

avatar Harmageddon
Harmageddon - comment - 3 Oct 2018

Merged staging to include the changes from #17552.

@mbabker With the current API, I don't see any alternative to this implementation.

avatar Harmageddon Harmageddon - change - 3 Oct 2018
Status Ready to Commit Closed
Closed_Date 0000-00-00 00:00:00 2018-10-03 10:21:59
Closed_By Harmageddon
Labels Added: ?
avatar Harmageddon Harmageddon - close - 3 Oct 2018
avatar Harmageddon Harmageddon - change - 3 Oct 2018
Status Closed New
Closed_Date 2018-10-03 10:21:59
Closed_By Harmageddon
Labels Removed: ?
avatar Harmageddon Harmageddon - change - 3 Oct 2018
Status New Pending
avatar Harmageddon Harmageddon - reopen - 3 Oct 2018
avatar Harmageddon Harmageddon - change - 3 Oct 2018
Status Pending Ready to Commit
avatar Harmageddon
Harmageddon - comment - 3 Oct 2018

(sorry, I accidentally hit the wrong button)


This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/14189.

avatar Hackwar
Hackwar - comment - 18 Jan 2019

Please see #12414. That might have an impact on this PR.

avatar Harmageddon
Harmageddon - comment - 18 Jan 2019

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.

avatar Harmageddon Harmageddon - change - 18 Jan 2019
Status Ready to Commit Closed
Closed_Date 0000-00-00 00:00:00 2019-01-18 19:29:20
Closed_By Harmageddon
Labels Added: ?
avatar Harmageddon Harmageddon - close - 18 Jan 2019
avatar wilsonge
wilsonge - comment - 21 Mar 2019

Just for the record I'd definitely be interested in seeing this for Joomla 4!

avatar Harmageddon
Harmageddon - comment - 31 Aug 2019

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?
@HLeithner / @wilsonge what do you think?

avatar zero-24
zero-24 - comment - 31 Aug 2019

Correct. All 3.x changes are merged up to 4.0 before the final release.

Add a Comment

Login with GitHub to post a comment