La forma más fácil de hacer esto es usar $ form_state. En su método formBuild (), tiene un if / else o switch basado en algo como $form_state['step']y muestra diferentes elementos de formulario. Luego, tiene lo mismo en su devolución de llamada de envío o tiene varias devoluciones de llamada de envío, que hacen algo a un objeto en $ form_state que está construyendo, cambie el paso y establezca el $form_state['rebuild']indicador en VERDADERO.
Hay algunas desventajas de ese enfoque, por lo que (entre otras razones) se creó el asistente de formularios ctools. Puede complicarse si tiene varios pasos y tiene que definir todo eso en una sola función / clase de formulario y todo sucede en las solicitudes POST.
Lo que hace el asistente de formularios de ctools es agrupar múltiples formularios separados y controlar la navegación de uno a otro. También usa el caché de objetos de ctools para almacenar su objeto en lugar de $ form_state, porque eso ya no se comparte entre sus formularios.
Mientras que el sistema no existe, sin embargo, los ctools objeto de caché se ha portado a 8.x y ahora se llama tempstore usuario, disponible como un servicio: \Drupal::service('user.private_tempstore')(antes 8,0-Beta8 llama user.tempstore). Esta es una capa en la parte superior del almacén de valores de clave expirables que introduce la propiedad de los datos almacenados allí. Entonces, esto es lo que impulsa el conocido mensaje en las vistas de que un usuario diferente está editando esa vista y está bloqueado por esa razón. Otra ventaja sobre el uso de $ _SESSION para eso es que sus datos solo deben cargarse cuando sea necesario, cuando está editando 3 vistas, luego usar $ _SESSION significaría que debe cargarlos y transportarlos en cada solicitud de página.
Si no necesita eso, puede confiar en la sesión o también ponerla directamente en un almacén de valores de clave expirable ($ form_state también se almacena allí ahora, no un pseudo-caché como estaba en 7.x).
Sin embargo, el sistema de configuración no es una buena combinación. Eso no está destinado al contenido por usuario (o al contenido), ya que en realidad no se escala para almacenar miles o decenas de miles de registros y puede hacer algunas suposiciones para precargar todo lo que pueda necesitar en una solicitud de página determinada ( todavía no, pero hay un problema para que eso suceda)
Una pregunta más sobre tu respuesta. Esta podría ser una pregunta tonta: ¿\ Drupal :: service ('user.tempstore') también está disponible para usuarios anónimos?
Normalmente, puede almacenar valores de formulario entre los pasos utilizando el caché de objetos de cTools (similar a los formularios de varios pasos en Drupal 7 ), o mediante $form_state(según este tutorial ).
En Drupal 8 puede heredar la FormBaseclase para crear una nueva clase de varios pasos.
En primer lugar, necesitaría crear la clase base que se encargará de inyectar las dependencias necesarias.
Agruparemos todas las clases de formulario y las colocaremos dentro de una nueva carpeta llamada Multistepubicada dentro del Formdirectorio de complementos de nuestro módulo de demostración. Esto es puramente por tener una estructura limpia y poder determinar rápidamente qué formularios son parte de nuestro proceso de formularios de varios pasos.
Aquí está el código de demostración (para el MultistepFormBase.phparchivo):
/**
* @file
* Contains \Drupal\demo\Form\Multistep\MultistepFormBase.
*/namespaceDrupal\demo\Form\Multistep;useDrupal\Core\Form\FormBase;useDrupal\Core\Form\FormStateInterface;useDrupal\Core\Session\AccountInterface;useDrupal\Core\Session\SessionManagerInterface;useDrupal\user\PrivateTempStoreFactory;useSymfony\Component\DependencyInjection\ContainerInterface;abstractclassMultistepFormBaseextendsFormBase{/**
* @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
*/publicfunction __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}
*/publicstaticfunction create(ContainerInterface $container){returnnewstatic(
$container->get('user.private_tempstore'),
$container->get('session_manager'),
$container->get('current_user'));}/**
* {@inheritdoc}.
*/publicfunction 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.
*/protectedfunction 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.
*/protectedfunction deleteStore(){
$keys =['name','email','age','location'];foreach($keys as $key){
$this->store->delete($key);}}}
Luego puede crear la clase de formularios real dentro de un archivo llamado MultistepOneForm.php:
En el buildForm()método estamos definiendo nuestros dos elementos de forma ficticia. Tenga en cuenta que estamos recuperando la definición de formulario existente de la clase principal primero. Los valores predeterminados para estos campos se establecen como los valores encontrados en la tienda para esas claves (de modo que los usuarios puedan ver los valores que completaron en este paso si vuelven a ello). Finalmente, estamos cambiando el valor del botón de acción a Siguiente (para indicar que este formulario no es el último).
En el submitForm()método guardamos los valores enviados a la tienda y luego redirigimos al segundo formulario (que se puede encontrar en la ruta demo.multistep_two). Tenga en cuenta que no estamos haciendo ningún tipo de validación aquí para mantener el código ligero. Pero la mayoría de los casos de uso requerirán alguna validación de entrada.
Y actualice su archivo de enrutamiento en el módulo de demostración ( demo.routing.yml):
Dentro del submitForm()método, guardamos nuevamente los valores en la tienda y los diferimos a la clase padre para conservar estos datos de la forma que mejor le parezca. Luego redirigimos a la página que queramos (la ruta que usamos aquí es falsa).
Ahora deberíamos tener un formulario de varios pasos en funcionamiento que utilice el PrivateTempStorepara mantener los datos disponibles en múltiples solicitudes. Si necesitamos más pasos, todo lo que tenemos que hacer es crear algunos formularios más, agregarlos entre los existentes y hacer un par de ajustes.
luego extienda la clase en src/Controller/MyWizardForm.php:
<?php/**
* @file
* Contains \Drupal\MyModuleMultistep\Controller\MyWizardForm
*/namespaceDrupal\MyModuleMultistep\Controller;/**
* Wrapping controller for wizard forms that serve as the main page body.
*/classMyWizardFormextendsWizardFormController{}
¿Conoces un ejemplo que pueda ayudar a entender cómo usar el asistente multipaso CTools?
Duncanmoo
1
@Duncanmoo No tengo, pero siéntase libre de hacer otra pregunta con un problema específico que tenga, o buscar en los Tests/Wizard/CToolsWizard*archivos donde puede encontrar algunas pruebas (por ejemplo testWizardSteps).
Normalmente, puede almacenar valores de formulario entre los pasos utilizando el caché de objetos de cTools (similar a los formularios de varios pasos en Drupal 7 ), o mediante
$form_state
(según este tutorial ).En Drupal 8 puede heredar la
FormBase
clase para crear una nueva clase de varios pasos.En el artículo Cómo crear formularios de varios pasos en Drupal 8 , puede encontrar una manera sencilla de crear un formulario de varios pasos en Drupal 8.
En primer lugar, necesitaría crear la clase base que se encargará de inyectar las dependencias necesarias.
Aquí está el código de demostración (para el
MultistepFormBase.php
archivo):Luego puede crear la clase de formularios real dentro de un archivo llamado
MultistepOneForm.php
:Y actualice su archivo de enrutamiento en el módulo de demostración (
demo.routing.yml
):Finalmente, cree la segunda forma (
MultistepTwoForm
):fuente
El asistente de varios pasos que ha mencionado, ya está integrado con CTools, consulte: Soporte de asistente para 8.x-3.x , por lo que puede considerar ampliarlo
your_module.services.yml
, por ejemploluego extienda la clase en
src/Controller/MyWizardForm.php
:fuente
Tests/Wizard/CToolsWizard*
archivos donde puede encontrar algunas pruebas (por ejemplotestWizardSteps
).