A maneira mais fácil de fazer isso é usar $ form_state. No seu método formBuild (), você tem um if / else ou alterna com base em algo como $form_state['step']e exibe diferentes elementos de formulário. Então você tem o mesmo no seu retorno de chamada de envio ou vários retornos de chamada de envio, que fazem algo com um objeto em $ form_state que você está construindo, altere a etapa e defina o $form_state['rebuild']sinalizador como TRUE.
Existem algumas desvantagens nessa abordagem, e é por isso que (entre outros motivos) o assistente de formulário ctools foi criado. Pode ser complicado se você tiver várias etapas e precisar definir tudo isso em um único formulário de função / classe e tudo acontecer nas solicitações POST.
O que o assistente de formulário ctools faz é agrupar vários formulários separados e controlar a navegação de um para o outro. Você também usa o cache de objetos ctools para armazenar seu objeto em vez de $ form_state, porque isso não é mais compartilhado entre seus formulários.
Embora esse sistema ainda não exista, o cache do objeto ctools foi portado para 8.x e agora é chamado de tempstore do usuário, disponível como um serviço: \Drupal::service('user.private_tempstore')(antes da 8.0-beta8 chamada user.tempstore). Essa é uma camada no topo do armazenamento de valores-chave expirável que introduz a propriedade dos dados armazenados. Portanto, é isso que alimenta a mensagem conhecida nas visualizações de que um usuário diferente está editando essa visualização e está bloqueada por esse motivo. Outra vantagem sobre o uso de $ _SESSION é que seus dados só precisam ser carregados quando necessário, quando você estiver editando três visualizações, e usar $ _SESSION significaria que você teria que carregar e carregá-los em todas as solicitações de página.
Se você não precisar disso, poderá confiar na sessão ou também colocá-la diretamente em um armazenamento de valores-chave expirável ($ form_state também está armazenado lá agora, não em um pseudo-cache como no 7.x).
O sistema de configuração, no entanto, não é uma boa correspondência. Isso não se destina ao conteúdo por usuário (ou ao conteúdo), pois não é realmente dimensionável para armazenar milhares ou dezenas de milhares de registros e pode fazer algumas suposições para pré-carregar tudo o que é necessário em uma determinada solicitação de página ( ainda não, mas há um problema para fazer isso acontecer)
Mais uma pergunta sobre sua resposta. Esta pode ser uma pergunta boba: \ Drupal :: service ('user.tempstore') também está disponível para usuários anônimos?
Normalmente, você pode armazenar valores de formulário entre as etapas, usando o cache de objeto do cTools (semelhante aos formulários de várias etapas do Drupal 7 ) ou através do $form_state(conforme este tutorial ).
No Drupal 8, você pode herdar a FormBaseclasse para criar uma nova classe de várias etapas.
Primeiro, você precisaria criar a classe base que será responsável por injetar as dependências necessárias.
Agruparemos todas as classes de formulário e as colocaremos em uma nova pasta chamada Multisteplocalizada no Formdiretório de plugins do nosso módulo de demonstração. Isso é apenas para ter uma estrutura limpa e ser capaz de dizer rapidamente quais formulários fazem parte do nosso processo de formulários de várias etapas.
Aqui está o código de demonstração (para MultistepFormBase.phparquivo):
/**
* @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);}}}
Em seguida, você pode criar a classe de formulários real dentro de um arquivo chamado MultistepOneForm.php:
No buildForm()método, estamos definindo nossos dois elementos de forma fictícia. Observe que estamos recuperando a definição de formulário existente da classe pai primeiro. Os valores padrão para esses campos são definidos como os valores encontrados na loja para essas chaves (para que os usuários possam ver os valores preenchidos nesta etapa, se voltarem a ele). Por fim, estamos alterando o valor do botão de ação para Avançar (para indicar que esse formulário não é o final).
No submitForm()método, salvamos os valores enviados na loja e, em seguida, redirecionamos para o segundo formulário (que pode ser encontrado na rota demo.multistep_two). Lembre-se de que não estamos fazendo nenhum tipo de validação aqui para manter o código leve. Mas a maioria dos casos de uso exigirá alguma validação de entrada.
E atualize seu arquivo de roteamento no módulo de demonstração ( demo.routing.yml):
Dentro do submitForm()método, salvamos novamente os valores na loja e adiamos para a classe pai para persistir esses dados da maneira que achar melhor. Em seguida, redirecionamos para a página que desejamos (a rota que usamos aqui é fictícia).
Agora devemos ter um formulário de várias etapas que use o PrivateTempStorepara manter os dados disponíveis em várias solicitações. Se precisarmos de mais etapas, tudo o que precisamos fazer é criar mais algumas formas, adicioná-las entre as existentes e fazer alguns ajustes.
estenda a classe em 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{}
você conhece um exemplo que possa ajudar a entender como usar o assistente de várias etapas do CTools?
Duncanmoo 07/07
1
@ Duncanmoo Eu não tenho, mas sinta-se à vontade para fazer outra pergunta com um problema específico que você está tendo ou procurar Tests/Wizard/CToolsWizard*arquivos onde você pode encontrar alguns testes (por exemplo testWizardSteps).
Normalmente, você pode armazenar valores de formulário entre as etapas, usando o cache de objeto do cTools (semelhante aos formulários de várias etapas do Drupal 7 ) ou através do
$form_state
(conforme este tutorial ).No Drupal 8, você pode herdar a
FormBase
classe para criar uma nova classe de várias etapas.No artigo Como criar formulários de várias etapas no Drupal 8, você pode encontrar uma maneira simples de criar um formulário de várias etapas no Drupal 8.
Primeiro, você precisaria criar a classe base que será responsável por injetar as dependências necessárias.
Aqui está o código de demonstração (para
MultistepFormBase.php
arquivo):Em seguida, você pode criar a classe de formulários real dentro de um arquivo chamado
MultistepOneForm.php
:E atualize seu arquivo de roteamento no módulo de demonstração (
demo.routing.yml
):Por fim, crie o segundo formulário (
MultistepTwoForm
):fonte
O assistente de várias etapas que você mencionou, já está integrado ao CTools, consulte: Assistente de Suporte para 8.x-3.x , para que você possa estendê-lo
your_module.services.yml
, por exemploestenda a classe em
src/Controller/MyWizardForm.php
:fonte
Tests/Wizard/CToolsWizard*
arquivos onde você pode encontrar alguns testes (por exemplotestWizardSteps
).