8000 Form handleRequest() does not work properly. · Issue #8261 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

Form handleRequest() does not work properly. #8261

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

Closed
mitris opened this issue Jun 12, 2013 · 39 comments
Closed

Form handleRequest() does not work properly. #8261

mitris opened this issue Jun 12, 2013 · 39 comments

Comments

@mitris
Copy link
mitris commented Jun 12, 2013

From symfony docs:

New in version 2.3: The handleRequest() method was added in Symfony 2.3. Previously, the $request was passed to the submit method - a strategy which is deprecated and will be removed in Symfony 3.0. For details on that method, see Passing a Request to Form::submit() (deprecated).

I'm confused with form binding. In docs says that submit method is deprecated, but when I generate CRUD with symfony generator, it puts bind method for form handling. In code above bind method placed comment that contains next:

     * Alias of {@link submit()}.
     * @deprecated Deprecated since version 2.3, to be removed in 3.0. Use {@link submit()} instead.

So, two functions was deprecated? Okay, when I use handleRequest in my controllers it does not work with forms submitted with PUT method. What method will correctly use for form handling?

@stof
Copy link
Member
stof commented Jun 12, 2013

the doc does not say that submit() is deprecated (it is not). It says that passing the Request object to submit() directly is deprecated (but will still work until 3.0)

@stof stof closed this as completed Jun 12, 2013
@mitris
Copy link
Author
mitris commented Jun 12, 2013

Okay, but why handleRequest does not handle PUT method? Or it's normal?

8000

@tetranz
Copy link
tetranz commented Jun 13, 2013

I have the same problem. handleRequest does not seem to work with PUT.

After handleRequest($request), isSubmitted() is true but isValid() is false even though there are no errors. Same code works fine with a POST.

@pine3ree
Copy link

Confirming the same issue with PUT method

In my case isSubmitted() return false.

I noticed that in:
Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationRequestHandler
line 40
$method = $form->getConfig()->getMethod() is "POST"
$request->getMethod() is "PUT"

so handleRequest returns null in line 41.

To solve temporarily there are many options:

  • create the form passing an options array in your CRUD controllers:

$myForm = $this->createForm(new MyType(), $myEntity, array('method' => 'PUT'));

  • using a standard POST request

basically the value for the hidden input "_method" must match the form method.

@paul8046
Copy link

I'm having the same issue. The following PUT action controller does not save the new $object (and $form->isValid() incorrectly returns false):

    public function putAction(Object $object, Request $request) {
        $form = $this->createForm(new ObjectType(), $object);
        $form->handleRequest($request);

        if (!$form->isValid()) {
            throw new HttpException(Codes::HTTP_BAD_REQUEST);
        }

        $em = $this->getDoctrine()->getManager();
        $em->flush();
    }

But by replacing $form = $this->createForm(new ObjectType(), $object); with $form = $this->createForm(new ObjectType(), $object, array('method' => 'PUT')); the method works as expected.

@stof
Copy link
Member
stof commented Jun 23, 2013

If you use the handleRequest method, the HTTP method indeed needs to match the method set in the form (either through the method option when building it or through setMethod after that), otherwise it will not be bound

@MasterB
Copy link
Contributor
MasterB commented Jun 27, 2013

If've the same Problem with PUT!

The doc says to use and it should be ok.
So there is a bug with handleRequest
This issue should not to be closed!

Hack:
in Controller Action set the method explizit:
$editForm = $this->createForm(new DepartementType(), $entity, array('method' => 'PUT'));

@tetranz
Copy link
tetranz commented Jun 27, 2013

Thanks to the posts here, I don't think this is a bug although I have found it to be a bit confusing.

@stof : I have this working okay with the method option but where is the setMethod you mentioned? Form doesn't have a setMethod.

I'm still a little confused about what is the recommended or best practice with handleRequest, especially in a CRUD situation. Is it true to say that handleRequest makes it easier to have one action method for both the GET and POST (or PUT) by avoiding the need for if ($request->isMethod('POST'))? You always simply do handleRequest and then check $form->isValid(). If the request method is anything other than the method option on the form object then isValid() is false so the code will fall through to display the view both when it's the initial display or a submission with errors. I think I've got it now. :) I've been creating separate action methods like what the console CRUD generator produces which seems cleaner but I guess this saves some code.

@stof
Copy link
Member
stof commented Jun 27, 2013

@tetranz sorry, it is not on the Form but on the FormConfig (available through $form->getConfig()). but it is simpler to pass the option when you control the creation of the form

@kor3k
Copy link
Contributor
kor3k commented Jul 10, 2013

stof
If you use the handleRequest method, the HTTP method indeed needs to match the method set in the form (either through the method option when building it or through setMethod after that), otherwise it will not be bound

but this disallows you to set the method in the twig template (unless you also alter the controller part for every form and action).

the method matching check really should be optional (perhaps enabled by default, but optional).

@stof
Copy link
Member
stof commented Jul 10, 2013

@kor3k Using handleRequest is optional. If you want to do things manually, use submit() and pass the submitted data

@kor3k
Copy link
Contributor
kor3k commented Jul 10, 2013

i know, but i'd like to use handleRequest but without the method check.

let's say i have three simple actions - put, post, patch - and all three share the same form creation and data persisting logic. then, i set the proper form method in twig.

but because of that method check in handleRequest, i must either not use handleRequest, or set the method in the controller (unnecessary overhead).

while handleRequest(FormInterface $form, $request = null , $matchRequestMethod = true) would be elegant solution.

@jakzal
Copy link
Contributor
jakzal commented Jul 11, 2013

@kor3k using a flag to change a behaviour of a method is a bad practice since the flag suggests that a method does more than one thing.

As @stof suggested, just use the submit() method, which does exactly the same thing as handleRequest() but without a method check. You can use the $request->request->get('form_name') to get an array of submitted values and pass it to the submit() method.

@diogotozzi
Copy link

Same confusion on Symfony 2.4. Had to set the parameter $this->createFormBuilder('someType', $entity, array('method' => 'DELETE')); in order to use handleRequest()

@kozborn
Copy link
kozborn commented Jul 24, 2014

Hi, I have some trouble with handleRequest:

Here is my code:

public function putAssetAction(Request $request, $id){
    $em = $this->getDoctrine()->getManager();
    $entity = $em->getRepository( 'BudgetBundle:Asset' )->find( $id );
    $form = $this->createForm( new AssetType(), $entity, array('method' => 'PUT') );
    $form->handleRequest($request);

The problem is that form bind data correctly but form isValid() return false because of isSubmitted() is false

But $form->bind() is also not working, because it is a PUT request.

@webmozart
Copy link
Contributor

@kozborn Could you open a new issue for your problem? Please also create a fork of symfony-standard which reproduces your problem, then we can help you to resolve it much faster. :)

@bmeynell
Copy link

Same problem using GET.

handleRequest():

        $form = $this                                                              
            ->get('form.factory')                                                  
            ->createNamedBuilder(null, 'my_search_form', new MySearch())
            ->setMethod('GET')                                                     
            ->getForm();                                                           

            $form->handleRequest($request); 

            $form->isValid(); // FALSE

submit():

        $form = $this                                                              
            ->get('form.factory')                                                  
            ->createNamedBuilder(null, 'my_search_form', new MySearch())
            ->setMethod('GET')                                                     
            ->getForm();                                                           

            $form->submit($request); 

            $form->isValid(); // TRUE

@DougHayward
Copy link

I've been having an issue when trying to update an entity.

1.Fill in form
2.Click update
3. Page refreshes but hasn't changed any of the data.

The Strange thing is it works fine in dev mode just not in production, and it's all my forms not just one. I've tried reverting all form views back to standard but has no effect and it's not just my local server it happens on I tried it on my production server also and it still fails.
But the create action works perfectly.

Could this be the same 'put' issue? Will changing put in the action to post solve my issue?

I'd try it now but won't be at my pc for a while so searching for the answer now .

Synfony2.5


EDIT

Changing PUT to POST worked as far as Updating/Editing goes, but now I've moved onto DELETE and again nothing happens?


EDIT

As the above comment mentions

$form->submit($request); instead of $form->handleRequest($request); fixes everything...

@samuel4x4
Copy link
samuel4x4 commented Dec 6, 2016

@BonnieDoug I don't think you can pass the entire $request to the submit() method, instead of that just the $request->request->get('form_name') array should be submitted.

@mote0230
Copy link
mote0230 commented Jan 24, 2017

3 years later and $form->handleRequest($request) followed by form->isValid() still returns false with no error message at all if you use PUT without also having created the form with PUT method. Nowhere to be seen in the docs. Wasted 2 hours on this.

@jakzal
Copy link
Contributor
jakzal commented Jan 24, 2017

@mote0230 this is a closed issue. Please open a new one if you think there's a bug and you'd like to report it. Don't forget to explain how to reproduce it. Best if you provide code example (i.e. fork of the standard edition and modify it to demonstrate the problem).

If you think there's anything we could improve in the docs, create an issue (or better a PR) for https://github.com/symfony/symfony-docs.

Thanks.

@garek007
Copy link
garek007 commented Feb 9, 2017

Agree with mote0230, nothing here has fixed my problem either. I found that for me, I had manually coded the form and my token was causing isValid() to fail. Using Symfony's built in twig form generator with the auto generated form type got everything working again.

@kor3k
Copy link
Contributor
kor3k commented Feb 10, 2017

well IMHO the biggest problem here is it fails silently. users must spend time to investigate what went wrong and that's just a PITA.
i understand that throwing an error would be a BC, but you should understand that silent fail is just wrong.
also, this problem still exists.

to solve this, the handleRequest should behave like this:

  • if the form's method IS NOT set in the form config (ie. is NULL), then handleRequest should be method agnostic, ie. accept ANY used method

  • if the form's method IS set, and the used method does not match, it should log an error into logger rather than throwing an error (to avoid BC)

@HeahDude
Copy link
Contributor

Hey @kor3k, fist from my point of view, saying that handleRequest " it fails silently", is wrong.

Handle request just call a RequestHandler it decides if it submits the form for a given request.

It happens that the default handler just submit the form method matches the request one.

If one needs a different behavior, no need to wait for a new feature, just use a custom handler.

@kor3k
Copy link
Contributor
kor3k commented Feb 10, 2017

@HeahDude well, it does fail silently because it does not tell the reason why it did not submit the form. and the reason and behavior is hazily documented.
yes you can find answers in docs

Behind the scenes, this uses a NativeRequestHandler object to read data off of the correct PHP superglobals (i.e. $_POST or $_GET) based on the HTTP method configured on the form (POST is default).

By default, a form is submitted to the same URI that rendered the form with an HTTP POST request. This behavior can be changed using the action and method options (the method option is also used by handleRequest() to determine whether a form has been submitted):

but it's not obvious, you have to investigate.

the fact that it still bothers people means it's at least unintuitive.

@kor3k
Copy link
Contributor
kor3k commented Feb 10, 2017

also, why does the form have default method set to POST? why not make it method agnostic (null)?

the use case like using one specific form with different methods (controller actions) is IMHO quite common.
the fact you can set form's method in a view (twig) supports this logic.

but because of handleRequest's behavior, you cannot just set the form method and action in a view, you need to set the proper form method in a controller for each http method, which is a unnecessary overhead for no reason (from my POV).

why cannot handleRequest/form be method-agnostic? where null means any method is accepted and valid? (or via some other way to achieve this)

@HeahDude
Copy link
Contributor

the fact you can set form's method in a view (twig) supports this logic

What about the possibility to do:

public function someAction(Request $request)
{
    $form = $this->createForm(SomeType::class, null, [
        'method' => $request->getMethod(),
    ]);
}

?

@mote0230
Copy link

Funny that this get bumped today, as earlier i read a somewhat similar bug and handling (or lack of handling) brianc/node-postgres#1200

Countless manhours continue to be wasted.

@numediaweb
Copy link
numediaweb commented Jul 12, 2017

The reason for me why the form is not submitted is because of this line:

// Don't submit the form if it is not present in the request
return;

at vendor/symfony/symfony/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php:101
The problem is that the form is never submitted by the HttpFundationRequestHandler.

@JasonCoal
Copy link
JasonCoal commented Jul 12, 2017 via email

@kor3k
Copy link
Contributor
kor3k commented Jul 17, 2017

@HeahDude unnecessary overhead.

consider this: you have CRUD controller and for every action you use the same form type and the same form options. so you create a function like MyController::createForm( $data ), which provides the form for every CRUD action. the only difference is the method, so you set the method in twig.

but because of HttpFundationRequestHandler behaviour, you can't. only if you comment out the line @numediaweb mentioned or do overhead code as you proposed.

as i said, instead of defaulting the method to POST, HttpFundationRequestHandler should default to null. and when the method is null, then every method is accepted (not checked).

@HeahDude
Copy link
Contributor

so you set the method in twig

Sounds wrong to me. A built Form instance is strictly configured, so configuring it in a template only is a bad idea as it leads to such issue, the FormView is here to carry this out.

Btw, this is also why I think buttons should always be part of the Form tree and not be hardcoded in templates (in addition of levering nice features for them: clicked state, theming ...).

as i said, instead of defaulting the method to POST, HttpFundationRequestHandler should default to null. and when the method is null, then every method is accepted (not checked).

This is not possible since the method defines the submission behavior (whether to ignore missing fields), so POST must remain a default value (which is also the default for the html attribute).

@kor3k
Copy link
Contributor
kor3k commented Jul 28, 2017

A built Form instance is strictly configured, so configuring it in a template only is a bad idea as it leads to such issue, the FormView is here to carry this out.

but what is the use case for setting the form method in twig then?

This is not possible since the method defines the submission behavior (whether to ignore missing fields), so POST must remain a default value (which is also the default for the html attribute).

good point.
well the default behavior is to not ignore missing fields, so in method-agnostic way, it could stick with that.

but i must admit, this would be confusing. the same way current fail-silently behavior is.

so when this method-mismatch fail occurs, it should be at least logged at warning/error level.

@fnagel
Copy link
Contributor
fnagel commented Jun 2, 2018

Upgraded from 2.8 to 3.4 and wasted some hours on this. Why is this not mentioned in the upgrade guide? It's definitely is a BC.

@nicolas-grekas
Copy link
Member

Would you mind sending a PR against branch 2.8 doing so?

@fnagel
Copy link
Contributor
fnagel commented Jun 2, 2018

I can do that! Problem is I'm still not quite sure why this is an issue exactly but I was able to fix it for my project. A small notice on how to fix this should be no problem.

Correct me if I'm wrong, but shouldn't this be part of this file? https://github.com/symfony/symfony/blob/3.0/UPGRADE-3.0.md

@nicolas-grekas
Copy link
Member

This file yes, it exists on branch 2.8 also.

@fnagel
Copy link
Contributor
fnagel commented Jun 5, 2018

@nicolas-grekas Please see pending PR: #27500

fnagel added a commit to fnagel/symfony that referenced this issue Jun 8, 2018
fnagel added a commit to fnagel/symfony that referenced this issue Jun 18, 2018
fnagel added a commit to fnagel/symfony that referenced this issue Jun 25, 2018
fabpot added a commit that referenced this issue Jun 25, 2018
…quests (fnagel)

This PR was merged into the 2.8 branch.

Discussion
----------

Add note about changed form processing when using PUT requests

| Q             | A
| ------------- | ---
| Branch?       | 2.8 and up?
| Bug fix?      | no
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| License       | MIT

Added a note about changed form processing when using PUT requests as people still struggling with this change. Documenting it should help people to quickly fix this without struggling why some of their forms won't work any more after upgrading.

See #8261

Commits
-------

140b6c2 Add note about changed form processing when using PUT requests
@mohamedhafezqo
Copy link
mohamedhafezqo commented Aug 27, 2019

If you are using submit in Patch or Put action you can use it as the below

    $form->submit($request, false); 
    $form->isValid(); // TRUE

as the second parameter in $this->submit($request, $clearMissing) method is $clearMissing and defined as a default value by true

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

0