Drupal 创建一个 GET 表单实例

hrs 提交于 2021/07/21 - 11:14 , 周三

我多年来一直在构建 Drupal 表单,所以我非常熟悉使用 FormBase 类和表单 API 组合一个 Drupal 表单。当我本周尝试创建 GET 表单时,我意识到实际上需要考虑很多。所有表单都是使用 GET 请求构建的,这是我专门讨论的提交。默认情况下,Drupal 中的表单使用 POST 请求来提交其数据,虽然可以将表单转换为使用 GET 来提交数据,但没有很好的文档记录。

Drupal 中已经提供了几种 GET 表单。如果您查看视图过滤器表单或搜索表单,它们都通过 GET 请求处理提交。这些表单倾向于使用表单、钩子和控制器的组合来管理它们的呈现和结果。我想要的是一个 GET 表单的例子,它在 Drupal 表单对象中更加自包含。

要使用 GET 方法设置要提交的表单,请使用表单状态的 setMethod() 函数。

$form_state->setMethod('GET');

这绝不是整个故事,因为还有一些其他事情需要考虑。从如何从表单输入获取数据到考虑 URL 结构,一切都很重要。事实上,我会说创建 GET 表单需要一种与普通 POST 请求表单略有不同的表单查看方式。

作为如何设置 GET 表单的示例,我将采用一个简单的 POST 表单并将其转换为 GET 表单,详细说明所涉及的步骤。以下代码是一个标准的 Drupal 表单,它使用 POST 请求并将输入字段作为消息打印出来。

<?php
 
命名空间Drupal\mymodule\Form ;
 
使用Drupal\Core\Form\FormBase ;
使用Drupal\Core\Form\FormStateInterface ;
 
类MyModuleGetForm扩展FormBase {
 
  /**
   * {@inheritdoc}
   */
  公共 函数getFormId ( )  {
    返回 'mymodule_get_form' ;
  }
 
  /**
   * {@inheritdoc}
   */
  公共 函数buildForm (数组 $form , FormStateInterface $form_state )  {
    $form [ '输入' ]  =  [
      '#type'  =>  '文本框' ,
      '#title'  =>  $this -> t ( 'Input' ) ,
    ] ;
 
    $form [ '提交' ]  =  [
      '#type'  =>  '提交' ,
      '#value'  =>  '提交' ,
    ] ;
 
    返回 $form ;
  }
 
  /**
   * {@inheritdoc}
   */
  公共 函数submitForm ( array  & $form , FormStateInterface $form_state )  {
    $this -> messenger ( ) -> addMessage ( $form_state -> getValue ( 'input' ) ) ;
  }
 
}

首先要做的是将表单的动作更改为GET,这将导致表单通过GET请求提交。为此,我们只需添加 setMethod() 调用,传递 GET 参数。

公共 函数buildForm (数组 $form , FormStateInterface $form_state )  {
    $form_state -> setMethod ( 'GET' ) ;
 
    $form [ '输入' ]  =  [
      '#type'  =>  '文本框' ,
      '#title'  =>  $this -> t ( 'Input' ) ,
    ] ;
 
    $form [ '提交' ]  =  [
      '#type'  =>  '提交' ,
      '#value'  =>  '提交' ,
    ] ;
 
    返回 $form ;
  }

执行此操作后,您将很快意识到表单不再正确提交。单击提交按钮将刷新页面,但它实际上不再调用提交处理程序或打印出消息。这是因为当您制作 GET 表单时,它本质上断开了表单本身的任何验证和提交处理程序。稍后我会回到这个话题。

交换到 GET 表单的一个副作用是表单数据将被添加到 URL(这就是 GET 请求的工作方式)。这意味着用户输入的任何数据都将添加到页面的 URL 中。此外,因为 Drupal 为安全起见向表单添加了额外的元素,所以您的 URL 会很长。您可以期望上面的表单生成一个看起来像这样的 URL。

/mymodule-form?text=some+text&form_build_id=form-BquQgIxCGifjd6UvsK_alG8kDsV45khPG4VKm1AnMeI&form_id=mymodule_get_form&op=Submit

从技术上讲,我们只需要表单的开头(即“text=some-text”部分)即可工作,但 Drupal 的内部表单保护机制将 form_build_id 和 form_id 添加到 URL。提交按钮还将 op=Submit 添加到 URL。 

让我们首先解决 URL 问题,以便我们可以生成一些更好看的 URL。这部分是通过将提交按钮的“ #name”参数设置为空白来完成的。这会导致“op”为空,这意味着它不会被添加到 URL 中。form_build_idform_id 项目添加到我们的buildForm()方法后的形式(我们定义的形式),所以我们需要添加后生成步骤,使我们可以重新将其删除。这是通过使用表单签名中的“ #after_build ”项来完成的,它的参数是一个回调,因此我们引用了同一个类中的静态方法。 

这是新的 buildForm() 方法,添加了'#after_build ' 步骤和提交字段的空白 #name。

  公共 函数buildForm (数组 $form , FormStateInterface $form_state )  {
    $form_state -> setMethod ( 'GET' ) ;
 
    $form [ '输入' ]  =  [
      '#type'  =>  '文本框' ,
      '#title'  =>  $this -> t ( 'Input' ) ,
    ] ;
 
    $form [ '提交' ]  =  [
      '#type'  =>  '提交' ,
      '#value'  =>  '提交' ,
      // 防止 op 出现在查询字符串中。
      '#name'  =>  '' ,
    ] ;
 
    // 添加后构建步骤。
    $form [ '#after_build' ] [ ]  =  [ get_class ( $this ) ,  'afterBuild' ] ;
 
    返回 $form ;
  }

afterBuild() 静态方法非常简单。我们只需要删除 URL 中不需要的项目并返回更改后的表单。

标签