Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Form] Cannot submit form with custom HTTP method #26287

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
alekitto opened this issue Feb 23, 2018 · 10 comments
Closed

[Form] Cannot submit form with custom HTTP method #26287

alekitto opened this issue Feb 23, 2018 · 10 comments

Comments

@alekitto
Copy link
Contributor

alekitto commented Feb 23, 2018

Q A
Bug report? no
Feature request? yes
BC Break report? no
RFC? no
Symfony version 4.0.4

While the routing component correctly handles custom HTTP methods, the form component disallow configuring a form with a method which is not GET, PUT, POST, DELETE, PATCH.
When trying to create an action with a custom HTTP method, FormConfigBuilder::setMethod throws an InvalidArgumentException.

@xabbuh
Copy link
Member

xabbuh commented Feb 23, 2018

Can you please show the code you used and the full exception with a stack trace included that you got with that?

@alekitto
Copy link
Contributor Author

alekitto commented Feb 23, 2018

Controller:

/**
 * @Route(path="/users", methods={"RESET"})
 */
public function resetAction(Request $request)
{
    $builder = $this
        ->createFormBuilder([], [
            'method' => 'RESET',
        ])
        ->add('id', IntegerType::class);

    $form = $builder->getForm();
    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {
        // ...
    }

    return new Response();
}

Stacktrace:

Symfony\Component\Form\Exception\InvalidArgumentException:
The form method is "RESET", but should be one of "GET", "PUT", "POST", "DELETE", "PATCH".

  at vendor/symfony/form/FormConfigBuilder.php:794
  at Symfony\Component\Form\FormConfigBuilder->setMethod('RESET')
     (vendor/symfony/form/Extension/Core/Type/FormType.php:55)
  at Symfony\Component\Form\Extension\Core\Type\FormType->buildForm(object(FormBuilder), array('block_name' => null, 'disabled' => false, 'label' => null, 'label_format' => null, 'translation_domain' => null, 'auto_initialize' => true, 'trim' => true, 'required' => true, 'property_path' => null, 'mapped' => true, 'by_reference' => true, 'inherit_data' => false, 'compound' => true, 'action' => '', 'post_max_size_message' => 'The uploaded file was too large. Please try to upload a smaller file.', 'error_mapping' => array(), 'invalid_message' => 'This value is not valid.', 'invalid_message_parameters' => array(), 'allow_extra_fields' => false, 'extra_fields_message' => 'This form should not contain extra fields.', 'attr' => array(), 'data' => array(), 'data_class' => null, 'empty_data' => object(Closure), 'error_bubbling' => true, 'label_attr' => array(), 'method' => 'RESET', 'upload_max_size_message' => object(Closure), 'validation_groups' => null, 'constraints' => array()))
     (vendor/symfony/form/ResolvedFormType.php:126)
  at Symfony\Component\Form\ResolvedFormType->buildForm(object(FormBuilder), array('block_name' => null, 'disabled' => false, 'label' => null, 'label_format' => null, 'translation_domain' => null, 'auto_initialize' => true, 'trim' => true, 'required' => true, 'property_path' => null, 'mapped' => true, 'by_reference' => true, 'inherit_data' => false, 'compound' => true, 'action' => '', 'post_max_size_message' => 'The uploaded file was too large. Please try to upload a smaller file.', 'error_mapping' => array(), 'invalid_message' => 'This value is not valid.', 'invalid_message_parameters' => array(), 'allow_extra_fields' => false, 'extra_fields_message' => 'This form should not contain extra fields.', 'attr' => array(), 'data' => array(), 'data_class' => null, 'empty_data' => object(Closure), 'error_bubbling' => true, 'label_attr' => array(), 'method' => 'RESET', 'upload_max_size_message' => object(Closure), 'validation_groups' => null, 'constraints' => array()))
     (vendor/symfony/form/Extension/DataCollector/Proxy/ResolvedTypeDataCollectorProxy.php:95)
  at Symfony\Component\Form\Extension\DataCollector\Proxy\ResolvedTypeDataCollectorProxy->buildForm(object(FormBuilder), array('block_name' => null, 'disabled' => false, 'label' => null, 'label_format' => null, 'translation_domain' => null, 'auto_initialize' => true, 'trim' => true, 'required' => true, 'property_path' => null, 'mapped' => true, 'by_reference' => true, 'inherit_data' => false, 'compound' => true, 'action' => '', 'post_max_size_message' => 'The uploaded file was too large. Please try to upload a smaller file.', 'error_mapping' => array(), 'invalid_message' => 'This value is not valid.', 'invalid_message_parameters' => array(), 'allow_extra_fields' => false, 'extra_fields_message' => 'This form should not contain extra fields.', 'attr' => array(), 'data' => array(), 'data_class' => null, 'empty_data' => object(Closure), 'error_bubbling' => true, 'label_attr' => array(), 'method' => 'RESET', 'upload_max_size_message' => object(Closure), 'validation_groups' => null, 'constraints' => array()))
     (vendor/symfony/form/FormFactory.php:80)
  at Symfony\Component\Form\FormFactory->createNamedBuilder('form', object(ResolvedTypeDataCollectorProxy), array(), array('method' => 'RESET', 'data' => array()))
     (vendor/symfony/form/FormFactory.php:58)
  at Symfony\Component\Form\FormFactory->createBuilder('Symfony\\Component\\Form\\Extension\\Core\\Type\\FormType', array(), array('method' => 'RESET'))
     (vendor/symfony/framework-bundle/Controller/ControllerTrait.php:322)
  at Symfony\Bundle\FrameworkBundle\Controller\AbstractController->createFormBuilder(array(), array('method' => 'RESET'))
     (src/Controller/UserController.php:163)
  at App\Controller\UserController->resetAction(object(Request))
     (vendor/symfony/http-kernel/HttpKernel.php:149)
  at Symfony\Component\HttpKernel\HttpKernel->handleRaw(object(Request), 1)
     (vendor/symfony/http-kernel/HttpKernel.php:66)
  at Symfony\Component\HttpKernel\HttpKernel->handle(object(Request), 1, true)
     (vendor/symfony/http-kernel/Kernel.php:190)
  at Symfony\Component\HttpKernel\Kernel->handle(object(Request), 1, true)
     (vendor/symfony/http-kernel/Client.php:68)

@xabbuh
Copy link
Member

xabbuh commented Feb 23, 2018

Ah, I read your initial description too fast. That's indeed something that is not supported right now.

@alekitto
Copy link
Contributor Author

Oh, i thought it was simply a wrong check.
To build a proper PR, may i ask you what is the reason for this check? Maybe to exclude methods like HEAD, TRACE, OPTIONS and CONNECT?

@nicolas-grekas
Copy link
Member

Why don't you use standard verbs? POST can do pretty much anything. I'm not sure it make sense to support this in Symfony. We've always been standards first. Might seem small, but the current restriction eg helps detect typos, which is important for DX.

@alekitto
Copy link
Contributor Author

When implementing an API maybe a POST request does not describe your needs well enough.
In addition, the HTTP standard does not restrict the method names and allows extensions like WebDAV o CalDAV to specify their own methods. I understand the current restriction, but i see that the same is not applied to the routing component, for example.
Maybe a simpler way to extend the list of allowed methods other than override 3 classes (ResolvedFormTypeFactory, ResolvedFormType and FormBuilder) and a service could be implemented?

@linaori
Copy link
Contributor

linaori commented Feb 26, 2018

Considering this is something specific for the form framework, I would argue that you shouldn't be using forms for apis in the first place.

@alekitto
Copy link
Contributor Author

If I may, why not? Forms are powerful, highly configurable, event emitting and self-validating data mappers, why shouldn't be used? You can transform data, validate data even change the configuration of the form based on the data received by the client with a minimum effort.
Also, the documentation of the choice type suggest this in the choice_value documentation section.

@nicolas-grekas
Copy link
Member

Why not, that's correct :)
Would you like to submit a PR to add more allowed methods via configuration?

@alekitto
Copy link
Contributor Author

Sure! I've opened a PR, but I'm not sure if this is the best possibile solution of the problem. I look forward to hear your feedbacks

@fabpot fabpot closed this as completed Oct 10, 2018
fabpot added a commit that referenced this issue Oct 10, 2018
…tion (alekitto)

This PR was merged into the 4.2-dev branch.

Discussion
----------

[Form] allow additional http methods in form configuration

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #26287
| License       | MIT
| Doc PR        | TBD

In order to allow HTTP methods other than GET, PUT, POST, DELETE and PATCH, the `allowed_methods` option under `framework.form` configuration has been added.
This configuration option adds the specified methods to the `FormConfigBuilder` whitelist, allowing that methods be used in form configuration via `setMethod` or the `method` option.

The use-case, that has been discussed in #26287, required the usage of custom HTTP method for describing a resource in an API application.

Commits
-------

27d228c [Form] remove restriction on allowed http methods
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants