64. 表单定义示例

表单form是系统非常重要的一块功能,用于用户向系统提交信息,本主题为你展示如何在drupal8中定义和使用表单,至于表单API如何运作将在接下来的几个主题中详解。

 

表单四要素:

要定义一个表单,系统仅需要你提供四个信息,其他事情比如CSRF token攻击验证、渲染等将为你自动完成,非常贴心,需要的四个信息如下:

表单识别id:用于唯一标识表单、其他模块通过该id产生的钩子参与表单流程、缓存等

表单的构成:指示表单里面有哪些元素等

表单如何验证:验证用户输入的数据是否合法

提交如何处理:用户点击提交表单后,指示系统如何去处理提交值

 

因此系统为表单对象定义了以下接口:

\Drupal\Core\Form\FormInterface

在该接口中只有四个方法,分别规范了以上四种信息,系统只需要调用他们就可以进行表单运用了

所以当我们要定义运用一个表单时仅需要编写一个实现以上接口的表单类即可。

 

我们可以将表单分为单步表单single-step和多步表单multi-step,单步表单是最常使用的情况,指用户提交一次即完成所有信息的提交和处理,而多步表单需要多次进行提交才能收集和处理完成所有信息和事务,可以在上一步下一步之间导航,典型的列子是安装系统时进行的多次提交,本主题将向你展示这两种表单。

 

 

单步表单single-step应用实例:

我们来定义一个单步表单,假设模块名为“yunke”,然后定义一个表单类,文件为:

\yunke\src\Form\YunkeForm.php

内容为:

<?php

/**
 * @file
 * 示例,建立一个表单
 */
namespace Drupal\yunke\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;

class YunkeForm extends FormBase
{

    public function getFormId()
    {
        return 'yunke_form';
    }

    public function buildForm(array $form, FormStateInterface $form_state)
    {
        $form['phone_number'] = array(
            '#type' => 'tel',
            '#title' => $this->t('Your phone number'),
            );
        $form['actions']['#type'] = 'actions';
        $form['actions']['submit'] = array(
            '#type' => 'submit',
            '#value' => $this->t('Save'),
            '#button_type' => 'primary',
            );
        return $form;
    }

    public function validateForm(array & $form, FormStateInterface $form_state)
    {
        if (strlen($form_state->getValue('phone_number')) < 5) {
            $form_state->setErrorByName('phone_number', $this->t('The phone number is too short. Please enter a full phone number.@time',["@time"=>time()]));
        }
    }

    public function submitForm(array & $form, FormStateInterface $form_state)
    {
        drupal_set_message($this->t('Your phone number is @number', array('@number' => $form_state->
                getValue('phone_number'))));
    }

}

然后定义一个路由指向一个控制器,控制器中执行以下代码:

return  \Drupal::formBuilder()->getForm("\Drupal\yunke\Form\YunkeForm");

或者执行以下代码:

        $form_object=new \Drupal\yunke\Form\YunkeForm();
        $form_state=new \Drupal\Core\Form\FormState();
        return \Drupal::formBuilder()->buildForm($form_object, $form_state);

按照路由访问这个控制器,就可以看到表单了,针对表单还可以有专门的路由定义方法,如下:

yunke.routing.yml中添加一个表单专用路由:

yunke.form:
  path: '/yunke-form'
  defaults:
    _title: 'yunke form'
    _form: '\Drupal\yunke\Form\YunkeForm'
  requirements:
    _permission: 'access content'

然后访问:http://www.yourdomain.com/yunke-form就可以了,结果和以上访问控制器的方式是完全相同的

多步表单multi-step应用实例:

在多步表单中,每一步都需要一个表单类,她们联合起来做一些事情,同样,假设模块名为“yunke,我们先定义一个基类以提供每个表单类的共用功能,文件如下:

\yunke\src\Form\Multistep\MultistepFormBase.php

内容如下:

<?php

/**
 * @file
 * Contains \Drupal\yunke\Form\Multistep\MultistepFormBase.
 */

namespace Drupal\yunke\Form\Multistep;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Session\SessionManagerInterface;
use Drupal\user\PrivateTempStoreFactory;
use Symfony\Component\DependencyInjection\ContainerInterface;

abstract class MultistepFormBase extends FormBase
{

    /**
     * @var \Drupal\user\PrivateTempStoreFactory
     */
    protected $tempStoreFactory;

    /**
     * @var \Drupal\Core\Session\SessionManagerInterface
     */
    private $sessionManager;

    /**
     * @var \Drupal\Core\Session\AccountInterface
     */
    private $currentUser;

    /**
     * @var \Drupal\user\PrivateTempStore
     */
    protected $store;

    /**
     * Constructs a \Drupal\yunke\Form\Multistep\MultistepFormBase.
     *
     * @param \Drupal\user\PrivateTempStoreFactory         $temp_store_factory
     * @param \Drupal\Core\Session\SessionManagerInterface $session_manager
     * @param \Drupal\Core\Session\AccountInterface        $current_user
     */
    public function __construct(PrivateTempStoreFactory $temp_store_factory, SessionManagerInterface $session_manager, AccountInterface $current_user)
    {
        $this->tempStoreFactory = $temp_store_factory;
        $this->sessionManager = $session_manager;
        $this->currentUser = $current_user;

        $this->store = $this->tempStoreFactory->get('multistep_data');
    }

    /**
     * {@inheritdoc}
     */
    public static function create(ContainerInterface $container)
    {
        return new static(
            $container->get('user.private_tempstore'),
            $container->get('session_manager'),
            $container->get('current_user')
        );
    }

    /**
     * {@inheritdoc}
     */
    public function buildForm(array $form, FormStateInterface $form_state)
    {
        // Start a manual session for anonymous users.
        if ($this->currentUser->isAnonymous() && !isset($_SESSION['multistep_form_holds_session'])) {
            $_SESSION['multistep_form_holds_session'] = true;
            $this->sessionManager->start();
        }

        $form = array();
        $form['actions']['#type'] = 'actions';
        $form['actions']['submit'] = array(
            '#type'        => 'submit',
            '#value'       => $this->t('Submit'),
            '#button_type' => 'primary',
            '#weight'      => 10,
        );

        return $form;
    }

    /**
     * Saves the data from the multistep form.
     */
    protected function saveData()
    {
        // Logic for saving data.
        //$this->deleteStore();
        drupal_set_message($this->t('The form has been saved.'));
    }

    /**
     * Helper method that removes all the keys from the store collection used for
     * the multistep form.
     */
    protected function deleteStore()
    {
        $keys = ['name', 'email', 'age', 'location'];
        foreach ($keys as $key) {
            $this->store->delete($key);
        }
    }
}

然后定义第一个步骤需要的表单对象,文件如下:

\yunke\src\Form\Multistep\MultistepOneForm.php

内容如下:

<?php

/**
 * @file
 * Contains \Drupal\yunke\Form\Multistep\MultistepOneForm.
 */

namespace Drupal\yunke\Form\Multistep;

use Drupal\Core\Form\FormStateInterface;

class MultistepOneForm extends MultistepFormBase
{

    /**
     * {@inheritdoc}.
     */
    public function getFormId()
    {
        return 'multistep_form_one';
    }

    /**
     * {@inheritdoc}.
     */
    public function buildForm(array $form, FormStateInterface $form_state)
    {

        $form = parent::buildForm($form, $form_state);

        $form['name'] = array(
            '#type'          => 'textfield',
            '#title'         => $this->t('Your name'),
            '#default_value' => $this->store->get('name') ? $this->store->get('name') : '',
        );

        $form['email'] = array(
            '#type'          => 'email',
            '#title'         => $this->t('Your email address'),
            '#default_value' => $this->store->get('email') ? $this->store->get('email') : '',
        );

        $form['actions']['submit']['#value'] = $this->t('Next');

        return $form;
    }

    /**
     * {@inheritdoc}
     */
    public function submitForm(array &$form, FormStateInterface $form_state)
    {
        $this->store->set('email', $form_state->getValue('email'));
        $this->store->set('name', $form_state->getValue('name'));
        $form_state->setRedirect('yunke.multistep_two');
    }

}

再定义第二个步骤的表单对象,文件如下:

\yunke\src\Form\Multistep\MultistepTwoForm.php

内容如下:

<?php

/**
 * @file
 * Contains \Drupal\yunke\Form\Multistep\MultistepTwoForm.
 */

namespace Drupal\yunke\Form\Multistep;

use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;

class MultistepTwoForm extends MultistepFormBase
{

    /**
     * {@inheritdoc}.
     */
    public function getFormId()
    {
        return 'multistep_form_two';
    }

    /**
     * {@inheritdoc}.
     */
    public function buildForm(array $form, FormStateInterface $form_state)
    {

        $form = parent::buildForm($form, $form_state);

        $form['age'] = array(
            '#type'          => 'textfield',
            '#title'         => $this->t('Your age'),
            '#default_value' => $this->store->get('age') ? $this->store->get('age') : '',
        );

        $form['location'] = array(
            '#type'          => 'textfield',
            '#title'         => $this->t('Your location'),
            '#default_value' => $this->store->get('location') ? $this->store->get('location') : '',
        );

        $form['actions']['previous'] = array(
            '#type'       => 'link',
            '#title'      => $this->t('Previous'),
            '#attributes' => array(
                'class' => array('button'),
            ),
            '#weight'     => 0,
            '#url'        => Url::fromRoute('yunke.multistep_one'),
        );

        return $form;
    }

    /**
     * {@inheritdoc}
     */
    public function submitForm(array &$form, FormStateInterface $form_state)
    {
        $this->store->set('age', $form_state->getValue('age'));
        $this->store->set('location', $form_state->getValue('location'));

        // Save the data
        parent::saveData();
        $form_state->setRedirect('yunke.multistep_one');
    }
}

好了,现在需要用到的表单对象都有了,再来定义路由,在yunke.routing.yml中加入以下内容:

yunke.multistep_one:
  path: '/yunke/multistep-one'
  defaults:
    _form: '\Drupal\yunke\Form\Multistep\MultistepOneForm'
    _title: 'First form'
  requirements:
    _permission: 'access content'
yunke.multistep_two:
  path: '/yunke/multistep-two'
  defaults:
    _form: '\Drupal\yunke\Form\Multistep\MultistepTwoForm'
    _title: 'Second form'
  requirements:
_permission: 'access content'

一切就绪,重新安装“yunke”模块,访问:

http://www.yourdomain.com/yunke/multistep-one就可以了

你将看到表单呈现了,你可以提交数据,在上一步和下一步间导航等等

 

本主题就讲到这里,为你展现一个示例,为后续的表单api做准备,注:本主题所用示例来自网络,经云客修改整理后为你呈现。

这是2017年的最后一篇主题,祝大家新年快乐

 

 

 

 

本书共94小节:

评论 (写第一个评论)