Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork9.7k
[Form] Implemented CoreTypeGuesser for submit button detection#9592
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Conversation
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.
Boolean
cordoval commentedNov 23, 2013
do you think a note in the documentation should be made about not using |
FineWolf commentedNov 24, 2013
You can still use Worst comes to worst, you have to specify the type. Ping @bschussek |
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 logic will not work. An object being traversable does not mean it will always be handled through the adder and remover. This is even a very uncommon case (the only way I see to do it is to attach thecollection type on thegetIterator method). The adder and remover are on the parent object, not on the collection itself
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.
Logic modified. I had read PropertyAccessor wrong. If there is an adder and a remover however, we want to assumesubmit is there.
FineWolf commentedNov 26, 2013
Changes done... Ping @bschussek |
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.
IMO this should be moved to a static property:
privatestatic$nameToTypeMapping =array('submit' =>'submit','reset' =>'reset',);
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.
@bschussek: This would prevent someone from modifying the list of supported mappings thru inheritance.
Consider this scenario: Someone creates their ownbutton type (let's call itrandom for example sakes) and they want to allow$builder->add('random')... The way it is now, they can easily overridegetSupportedButtonTypeMappings() in a way that is agnostic to future modifications of the mappings as such:
/** * {@inheritDoc} */protected function getSupportedButtonTypeMappings(){ $mappings = parent::getSupportedButtonTypeMappings(); $mappings['random'] = 'random'; return $mappings;}and then change the%form.type_guesser.core.class% parameter to their overloaded class.
By making it aprivate static variable, the developer in the scenario above would have to redo all the work.
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.
If they provide their own type, they should be providing a separate guesser, not replacing the guesser of the core extension
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'm sorry@stof but Istrongly disagree. The whole point of having an object-oriented service container is to be able to replace specific services with your own implementation that extends the base implementation if you have a very small change to make.In fact, this is one of the main advantages of dependency injection coupled with the service locator pattern.
The use case above is a perfectly valid use case that happens all the time in software development. Forcing the user to copy-paste code into its own implementation to simply add what arguably should be a configurable element is, IMHO, an idiotic design decision. Ping@fabpot
In fact, this is something I'm doing in my own projects. For example, I extended the defaultProfilerListener to only save profiling information of non-404 exceptions whenonly_exceptions is enabled in the configuration. IfonKernelException would not of been overridable and theprofiler_listener.class parameter would not be available, I would of had to roll out my own completeProfilerListener implementation. That would of been costly and not at all elegant. Plus, this approach would of required me to update it manually when the Symfony version updates. That would of been utterly ridiculous.
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.
@FineWolf I'm not talking about the container here. I'm talking about the way the Form component works. Extending the core guesser to replace it can only be done by 1 package wanting to provide a new button type (the next one would need to be aware of the previous overwrite, which is impossible for shared stuff). The Form component lets many different guessers being registered, so registering a separate guesser is a fat better way to extend the form component than replacing the gusser of another extension.
Composition is most of the time a far better extension point than inheritance.
Your argument for making the class extendable is that other guesser may need to reuse the other protected properties to inspect the class. My own conclusion based on the same need is that these other protected methods should not be part of this type guesser but be in a collaborator instead (which can then be reused by other guessers)
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.
@stof The point is not to make it extendable for multiple packages, but on a special case basis. Of course if you are building a reusable bundle you would want to roll out your ownTypeGuesser, however there are special cases where for when you are building that one specific project in that one specific case, you might want to add a new supported button type, or maybe disable the support forreset and keep the one for submit.
Both are totally valid points. However I do not think we must be overly restrictive in this case. There are still valid use-cases for having aprotected function here.
In fact, having itprotected here does allow someone to register their implementation as a new TypeGuesser, keeping the logic of the original one and simply returning a new supported type.
At the end of the day, I'll go with whatever you guys decide. Just make an informed decision.
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 issue if we make it protected is that we have to maintain BC on it for the full 2.x lifetime (because changing a protected method is a BC rbeak fo people extending the class). This is why we use private everywhere unless we explicitly want to make it a supported extension point (and before switching a method to protected to add an extension point, we think about other ways to achieve the extension to decide whether switching to protected is the best way to provide it. As I said at the end of my command above, there might be better ways to achieve the use case)
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.
@stof I'll move the property detection logic in a separate class (which would allow otherTypeGuessers to use it) and make array private static as asked.
… specialized button type based on the field name and the underlying data_class
FineWolf commentedNov 26, 2013
@stof better? |
FineWolf commentedNov 27, 2013
Ping @bschussek |
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.
run php-cs-fixer
webmozart commentedMar 28, 2014
fabpot commentedMar 31, 2014
#10570 has been merged now. |
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.
It looks like much code duplication with the PropertyAccess component. We can probably reuse it which is a required dependency anyway. Maybe the newisReadable method, see#10570
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.
@Tobion you should have looked at the discussion first. The PR was already referenced
FineWolf commentedMar 31, 2014
#10570 requires an object to verify if the property is readable/writable or not.
Other than creating an instance of the data class (which we might not be able to due to constructor signature), I fail to see how#10570 will help us here. Ping@webmozart |
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.
Shouldn't this a regular method? As your creating a closure every time the camelize method is called (which can be quite allot).
webmozart commentedSep 25, 2014
@FineWolf Sorry for the late feedback! I'd really like to move the inspection features into the PropertyAccess component, otherwise we risk having two incompatible or at least different implementations here and there. I think it would be sufficient if There is one more problem (and that's the same for other guessers) which is that the "property_path" option is ignored, if set. This can probably be solved in the scope of#7868. |
webmozart commentedJun 16, 2015
I'm closing this since the PR is really rather large for replacing $form->add('submit','submit'); by $form->add('submit'); I want to prevent changing/adding big amounts of code if not really necessary. Thanks again@FineWolf! |
* The old behavior would of caused an exception to be thrown while binding the data.
Created during the Symfony Montreal Hackathon