मल्टीस्टेप / विज़ार्ड रूपों


10

मैं Drupal 8 के लिए एक मल्टीस्टेप / विजार्ड फॉर्म बनाने की कोशिश कर रहा हूं।

  • उपयोगकर्ता पहले नाम, अंतिम नाम फ़ील्ड में भरता है
  • अगले बटन पर क्लिक करता है
  • अधिक जानकारी भरता है
  • सबमिट बटन पर क्लिक करता है

वर्तमान में कई संसाधनों इस तरह Drupal 7 के लिए multistep या विज़ार्ड रूपों के लिए समर्पित कर रहे हैं एक और इस

दूसरी ओर, मुझे कुछ परेशानी हुई है जो कि ड्रुपल 8 मल्टीस्टेप / विजार्ड फॉर्म बनाने का "ड्रुपल" तरीका है।

मैंने कुछ शोध किया और लगा कि कई दृष्टिकोण हैं:

क्या Drupal 8 के लिए वे मान्य दृष्टिकोण हैं?

जवाबों:


12

ऐसा करने का सबसे आसान तरीका $ form_state का उपयोग करना है। अपने फॉर्मब्यूइल्ड () पद्धति में, आपके पास एक if / else है या किसी चीज़ के आधार पर स्विच करता है $form_state['step']और विभिन्न फ़ॉर्म तत्वों को प्रदर्शित करता है। तब आपके पास या तो आपके सबमिट कॉलबैक में समान हैं या आपके पास कई सबमिट कॉलबैक हैं, जो $ form_state में किसी ऑब्जेक्ट के लिए कुछ ऐसा करते हैं कि आप निर्माण कर रहे हैं, चरण बदलें और $form_state['rebuild']ध्वज को TRUE पर सेट करें ।

उस दृष्टिकोण के लिए कुछ डाउनसाइड हैं, यही वजह है कि (अन्य कारणों के बीच) ctools प्रपत्र विज़ार्ड बनाया गया था। यह जटिल हो सकता है यदि आपके पास कई चरण हैं और उन सभी को एक एकल रूप फ़ंक्शन / वर्ग में परिभाषित करना है और सब कुछ POST अनुरोधों में होता है।

Ctools प्रपत्र विज़ार्ड क्या करता है समूह एकाधिक, अलग-अलग रूप और एक से दूसरे में नेविगेशन को नियंत्रित करता है। आप अपनी ऑब्जेक्ट को $ form_state के बजाय संग्रहीत करने के लिए ctools ऑब्जेक्ट कैश का उपयोग भी करते हैं, क्योंकि वह अब आपके फ़ॉर्म में साझा नहीं किया गया है।

हालांकि यह प्रणाली अभी तक मौजूद नहीं है, ctools एक सेवा के रूप, वस्तु उपलब्ध कैश 8.x में पोर्ट गया है और अब उपयोगकर्ता tempstore कहा जाता है: \Drupal::service('user.private_tempstore')(पहले 8.0-beta8 कहा जाता है user.tempstore)। यह एक महत्वपूर्ण कुंजी मूल्य स्टोर के ऊपर एक परत है जो वहां संग्रहीत डेटा के स्वामित्व का परिचय देता है। तो यह वही है जो विचारों को अच्छी तरह से जानता है कि एक अलग उपयोगकर्ता वर्तमान में उस दृश्य को संपादित कर रहा है और यह उस कारण से बंद है। इसके लिए $ _SESSION का उपयोग करने पर एक और लाभ यह है कि आपके डेटा को केवल जरूरत पड़ने पर लोड करना पड़ता है, जब आप 3 दृश्य संपादित कर रहे होते हैं, तो $ _SESSION का उपयोग करने का मतलब होगा कि आपको उन्हें हर एक पृष्ठ अनुरोध पर लोड करना और ले जाना होगा।

यदि आपको इसकी आवश्यकता नहीं है, तो आप सत्र पर भरोसा कर सकते हैं या इसे सीधे एक महत्वपूर्ण कुंजी मूल्य स्टोर में डाल सकते हैं ($ form_state वहां अब भी संग्रहीत है, छद्म-कैश नहीं है जैसा कि 7.x में था)।

कॉन्फ़िगरेशन सिस्टम हालांकि एक अच्छा मैच नहीं है। इसका मतलब प्रति-उपयोगकर्ता सामग्री (या सभी सामग्री) के लिए नहीं है क्योंकि यह वास्तव में हजारों या दसियों हजार रिकॉर्डों को संग्रहीत करने का पैमाना नहीं है और किसी दिए गए पृष्ठ के अनुरोध पर इसे पूर्व लोड करने के लिए कुछ अनुमान लगा सकता है ( अभी तक नहीं, लेकिन ऐसा करने के लिए एक मुद्दा है)


आपके उत्तर के बारे में एक और सवाल। यह एक मूर्खतापूर्ण प्रश्न हो सकता है: अनाम उपयोगकर्ताओं के लिए भी उपलब्ध \ Drupal :: सेवा ('user.tempstore') है?
च्र्सजली

हाँ, यह anoymous उपयोगकर्ताओं के लिए सत्र आईडी पर वापस आ जाता है। देखें api.drupal.org/api/drupal/...
Berdir

4

आम तौर पर आप या तो cTools ऑब्जेक्ट कैश ( Drupal 7 में मल्टीस्टेप फॉर्म के समान ), या $form_state(इस ट्यूटोरियल के अनुसार ) के माध्यम से चरणों के बीच फॉर्म वैल्यू स्टोर कर सकते हैं ।

Drupal 8 में आप FormBaseएक नया मल्टीस्टेप क्लास बनाने के लिए क्लास इनहेरिट कर सकते हैं ।

Drupal 8 में मल्टी-स्टेप फॉर्म का निर्माण कैसे करें लेख में आप Drupal 8 में एक मल्टीस्टेप फॉर्म बनाने का एक सरल तरीका पा सकते हैं।

सबसे पहले, आपको आधार वर्ग बनाने की आवश्यकता होगी जो आवश्यक निर्भरता को इंजेक्ट करने के प्रभारी होंगे।

हम सभी फॉर्म कक्षाओं को एक साथ जोड़ेंगे और उन्हें हमारे डेमो मॉड्यूल Multistepके Formप्लगइन डायरेक्टरी के भीतर स्थित एक नए फ़ोल्डर के अंदर रखेंगे । यह विशुद्ध रूप से एक स्वच्छ संरचना होने और जल्दी से यह बताने में सक्षम है कि कौन से रूप हमारे मल्टीस्टेप फॉर्म प्रक्रिया का हिस्सा हैं।

यहाँ डेमो कोड ( MultistepFormBase.phpफ़ाइल के लिए) है:

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

namespace Drupal\demo\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\demo\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 goes here...
    $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);
    }
  }
}

तब आप एक फ़ाइल के अंदर वास्तविक रूप वर्ग बना सकते हैं, जिसे कहा जाता है MultistepOneForm.php:

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

namespace Drupal\demo\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('demo.multistep_two');
  }
}

में buildForm()विधि हम अपने दो डमी प्रपत्र तत्वों को परिभाषित कर रहे हैं। ध्यान दें कि हम पहले मूल वर्ग से मौजूदा फॉर्म परिभाषा को पुनः प्राप्त कर रहे हैं। इन फ़ील्ड्स के लिए डिफ़ॉल्ट मान उन कुंजियों के लिए स्टोर में पाए जाने वाले मानों के रूप में सेट किए जाते हैं (ताकि उपयोगकर्ता इस चरण में भरे गए मान देख सकें, यदि वे इस पर वापस आते हैं)। अंत में, हम एक्शन बटन का मान बदलकर नेक्स्ट (यह इंगित करने के लिए करते हैं कि यह फ़ॉर्म अंतिम नहीं है)।

में submitForm()विधि हम दुकान के पास जमा मूल्यों को बचाने और उसके बाद दूसरा रूप (मार्ग पर पाया जा सकता है पर अनुप्रेषित demo.multistep_two)। ध्यान रखें कि कोड को हल्का रखने के लिए हम यहां किसी प्रकार का सत्यापन नहीं कर रहे हैं। लेकिन अधिकांश उपयोग के मामले कुछ इनपुट सत्यापन के लिए कहेंगे।

और डेमो मोड में अपनी रूटिंग फ़ाइल को अपडेट करें ( demo.routing.yml):

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

अंत में, दूसरा फॉर्म बनाएं ( MultistepTwoForm):

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

namespace Drupal\demo\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('demo.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('some_route');
  }
}

submitForm()विधि के अंदर हम फिर से स्टोर में मूल्यों को सहेजते हैं और माता-पिता वर्ग को इस डेटा को किसी भी तरह से फिट रखने के लिए जारी रखते हैं। फिर हम जो भी पेज चाहते हैं उसे रीडायरेक्ट करते हैं (जिस रूट का हम यहां इस्तेमाल करते हैं वह डमी है)।

अब हमारे पास एक कार्यशील मल्टीस्टेप फॉर्म होना चाहिए जो PrivateTempStoreडेटा का उपयोग कई अनुरोधों पर उपलब्ध रखता है। अगर हमें और अधिक चरणों की आवश्यकता है, तो हमें केवल कुछ और रूप बनाने होंगे, उन्हें मौजूदा लोगों के बीच जोड़ना होगा और कुछ समायोजन करने होंगे।


1

Multistep जादूगर है कि आप उल्लेख किया है, यह पहले से ही CTools के साथ एकीकृत है, देखें: जादूगर समर्थन 8.x-3.x के लिए है, तो आप में यह विस्तार पर विचार कर सकते your_module.services.yml, जैसे

services:
  ctools.wizard.form:
    class: Drupal\MyModuleMultistep\Controller\MyWizardForm

फिर कक्षा का विस्तार करें src/Controller/MyWizardForm.php:

<?php

/**
 * @file
 * Contains \Drupal\MyModuleMultistep\Controller\MyWizardForm
 */

namespace Drupal\MyModuleMultistep\Controller;

/**
 * Wrapping controller for wizard forms that serve as the main page body.
 */
class MyWizardForm extends WizardFormController {

}

क्या आप एक ऐसे उदाहरण के बारे में जानते हैं जो यह समझने में मदद कर सकता है कि CTools मल्टीस्टेप विज़ार्ड का उपयोग कैसे करें?
डंकनमू

1
@Duncanmoo मेरे पास नहीं है, लेकिन बेझिझक एक अन्य प्रश्न पूछें जो कि आपके पास है, या उन Tests/Wizard/CToolsWizard*फाइलों में देखें जहां आपको कुछ परीक्षण मिल सकते हैं (जैसे testWizardSteps)।
kenorb
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.