Skip to content
This repository has been archived by the owner on Jan 8, 2020. It is now read-only.

Add element input filters before form input filters #5479

Closed
wants to merge 5 commits into from
Closed

Add element input filters before form input filters #5479

wants to merge 5 commits into from

Conversation

stldo
Copy link

@stldo stldo commented Nov 14, 2013

When preferFormInputFilter is set to false, input filters returned by the elements implementing InputProviderInterface are added to inputFilter before the form input filters. This way the inputs are validated as expected, e.g.: using email element, the email is validated before an user specified RecordExists runs.

Input filters returned by the element getInputSpecification() are added
to the chains before the form input filters returned by
getInputFilterSpecification(). Also, it creates the replace() method in
BaseInputFilter, that allows the filters to be replaced without having
to remove them first. As the filters must be merged,
preferFormInputFilter must be set to false on the forms.
@davidwindell
Copy link
Contributor

Thanks @saltoledo can you add;

$this->preferFormInputFilter = false;

above here; https://github.com/zendframework/zf2/blob/master/library/Zend/Form/Form.php#L646

And check all tests still pass.

@stldo
Copy link
Author

stldo commented Nov 14, 2013

@davidwindell, testWillUseFormInputFilterOverrideOverInputSpecificationFromElement() fails.

@davidwindell
Copy link
Contributor

@saltoledo can you change the order of the line below in that test and see if that fixes it?

$this->form->setPreferFormInputFilter(true);
$this->form->setInputFilter($filter);

I don't think anyone will have an issue with that. You can then remove the call to setPreferFormInputFilter(false) in my test making everything work out.

* Replace a named input
*
* @param string $name
* @return InputFilterInterface
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@return self

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just copied the comments from another method, the other methods in this class are using "@return InputFilterInterface". Anyway, this DocBlock was incomplete, I made it a bit more complete.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@stldo
Copy link
Author

stldo commented Nov 14, 2013

@davidwindell, these changes make everything work out, but I think that the preferFormInputFilter flag shouldn't be changed to false without user knowledge. From 2.2.4 its default value is true, and changing it on setInputFilter() call could lead to an unsteady behaviour. As in the test that was breaking, if the user sets preferFormInputFilter to true before setting the inputFilter, or even if this user relies on the default setting as being true, he expects that the provided inputFilter will override the default input specs of the form elements. On the other hand, you want to merge element specs with the input filter that you are providing, so you are expecting the behaviour of preferFormInputFilter set to false. In our application we have many custom form elements that implement InputProviderInterface, so since 2.2.4 update we simply extended the Form class and set preferFormInputFilter to false.

@samsonasik
Copy link
Contributor

for

return $this

the docblock should be

return self

see #4436 (comment)

@stldo
Copy link
Author

stldo commented Nov 15, 2013

@samsonasik, thanks for pointing out. I'll update the other docbloks in the committed files, is it ok?

@davidwindell
Copy link
Contributor

@saltoledo why not set the default value of preferforminputfilter to null, then we can check if a user has set it explicitly or not. I think that anyone who directly calls 'setInputFilter' is going to expect their input filter to take priority over the forms.

@samsonasik
Copy link
Contributor

@saltoledo you should only update the related changes to your PR, no need to update other to ease review.

@stldo
Copy link
Author

stldo commented Nov 15, 2013

@davidwindell I completely agree with you, the default value of preferFormInputFilter should be false, it is more intuitive. Would it not be better to open a new PR for it? See weierophinney@ce07861. @samsonasik thanks for your time, I'll update it right now.

@davidwindell
Copy link
Contributor

@saltoledo I agree too in our context however I can't see them wanting to change that again. Here's what I'd do;

  • Set the default value of preferFormInputFilter to null (instead of true or false)
  • All usages of that variable should then use the getPreferFormInputFilter function
  • getPreferFormInputFilter should return true if it is set to null or true
  • setInputFilter could then check if preferFormInputFilter is null and only if so, set it to false.

That should resolve all the issues and mean no changes to that test.

@stldo
Copy link
Author

stldo commented Nov 15, 2013

@davidwindell I think it's cleaner to use a $hasChangedPreferFormInputFilter and set it to true if setPreferFormInputFilter method is called. Then just check for it in setInputFilter and set preferFormInputFilter accordingly. This way testPreferFormInputFilterFlagIsEnabledByDefault won't break. But I'm kinda concerned about whenever someone calls setInputFilter he expects that element specs will be overridden if he isn't explicitly set preferFormInputFilter to its default value. Since 2.2.3, the forms in my application are breaking on every ZF release. Sometimes a change like this may cause more BC breaks to other people. Maybe the solution is turning preferFormInputFilter default to false again, i.e., if I use an email element, I want to use its defaults properties, including validators, so I expect that they validate the input before my validators gets into action. If I don't want to use this element property, I disable it setting preferFormInputFilter to true and use only the validators set for my form. The same with the select and other elements implementing InputProviderInterface. What do you think about it?

@davidwindell
Copy link
Contributor

@saltoledo You'll have to ask @weierophinney about that as there is a lot of history in the 2.2.3/2.2.4(hotfix) releases about it.

As I've said before I'm surprised this issue wasn't seen earlier as it completely broke all our forms as it did for you. Thanks for finding a solution.

p.s. I personally prefer the null approach (it's used elsewhere in the framework) over the hasChanged flag - can you get either approach implemented soon so we can push for a merge.

Set Form::$preferFormInputFilter to false if user don't explicitly set
its value and call Form::setInputFilter()
@stldo
Copy link
Author

stldo commented Nov 19, 2013

@davidwindell I've sent the changes. I'd implemented the hasChangedPreferFormInputFilter approach, as changing preferFormInputFilter to null would break testPreferFormInputFilterFlagIsEnabledByDefault().

@davidwindell
Copy link
Contributor

@weierophinney your thoughts?


if ($inputFilter->has($name)) {
$input->merge($inputFilter->get($name));
$inputFilter->replace($input, $name);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem with this approach is that replace is not in the interface. If the input filter implementation used does not have that method, we end up getting an error.

Two options:

  1. Duck-type: if (method_exists($inputFilter, 'replace'))
  2. Create a ReplaceableInputInterface with the replace method, and have the BaseInputFilter implement it. Then do an instanceof check: if ($inputFilter instanceof ReplaceableInputInterface).

The second is cleaner from an OOP perspective, and will ensure we include the functionality directly in the base interface in v3.

@davidwindell
Copy link
Contributor

@saltoledo can you implement the ReplaceableInputInterface so that we can get this merged asap?

@stldo
Copy link
Author

stldo commented Dec 12, 2013

@weierophinney I did as described in the second option. @davidwindell sorry for the delay, I have had a lot of work this week!

@davidwindell
Copy link
Contributor

Can someone merge this please, it's been 2 months now without further feedback.

Ping @Maks3w @weierophinney


namespace Zend\InputFilter;

interface ReplaceableInputInterface
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please a docblock describing the purpose of the interface

@weierophinney weierophinney added this to the 2.2.6 milestone Mar 3, 2014
@weierophinney weierophinney self-assigned this Mar 3, 2014
weierophinney added a commit that referenced this pull request Mar 3, 2014
Add element input filters before form input filters
weierophinney added a commit that referenced this pull request Mar 3, 2014
- Incorporates feedback from @Maks3w
weierophinney added a commit that referenced this pull request Mar 3, 2014
Forward port #5479

Conflicts:
	tests/ZendTest/Form/FormTest.php
Ocramius added a commit to doctrine/DoctrineORMModule that referenced this pull request Mar 13, 2014
Close #309

See zendframework/zendframework#5479

Compatibilizes with zendframework/zf2:~2.2.4, which uses `prefer_form_input_filter` by default
@stldo stldo deleted the form-input-filter-fix branch May 13, 2014 14:28
weierophinney added a commit to zendframework/zend-inputfilter that referenced this pull request May 15, 2015
…rm-input-filter-fix

Add element input filters before form input filters
weierophinney added a commit to zendframework/zend-inputfilter that referenced this pull request May 15, 2015
weierophinney added a commit to zendframework/zend-inputfilter that referenced this pull request May 15, 2015
weierophinney added a commit to zendframework/zend-inputfilter that referenced this pull request May 15, 2015
Forward port zendframework/zendframework#5479

Conflicts:
	tests/ZendTest/Form/FormTest.php
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants