Domanda Procedura consigliata per la creazione di form di pagine multiple Yii


Sto cercando di creare un modulo multipagina con Yii, ma sono abbastanza nuovo per PHP e Yii e mi sto chiedendo quale sia la procedura migliore per scrivere un modulo di più pagine. Finora, quello che sto pensando di fare è aggiungere un campo nascosto chiamato "step" che contiene il passo corrente in cui si trova l'utente nel modulo (il modulo è suddiviso in 3 passaggi / pagine). Con questo in mente, è così che ho intenzione di gestire l'utente cliccando sui pulsanti precedenti / successivi nel Controller:

public function actionCreate()
 {
  $userModel = new User;

  $data['activityModel'] = $activityModel; 
  $data['userModel'] = $userModel; 

  if (!empty($_POST['step']))
  {
   switch $_POST['step']:
    case '1':
     $this->render('create_step1', $data);
     break;

    case '2':
     $this->render('create_step2', $data);
     break;

  }else
  {
   $this->render('create_step1', $data);
  }
 }

Questo approccio ha senso? O sono fuori di testa e c'è un modo molto migliore e più ottimizzato per farlo in Yii / PHP?

Grazie!


23
2017-08-23 14:31


origine


risposte:


Ci sono un paio di modi per avvicinarsi a questo. Ti vedo pubblicato sul forum Yii, quindi presumo che tu abbia cercato anche lì, ma nel caso tu non l'abbia:

Quello che ho fatto è (solo per un semplice modulo ActiveRecord in 2 fasi) preso una singola azione e diviso in blocchi condizionali in base al nome del pulsante, che i POST Yii su un modulo presentano (nota: non funziona con ajax invia ). Quindi, a seconda del pulsante premuto, eseguo il rendering del modulo corretto e imposto lo scenario corretto sul mio modello per scopi di convalida.

Un campo "step" nascosto come te potrebbe avere lo stesso scopo del controllo del nome submitButton. Forse salverei il "passo" nello stato del modulo invece di aggiungere un campo nascosto, ma entrambi andrebbero bene.

Alcune persone usano l'attributo stateful activeForm per salvare i dati da un singolo passaggio nella procedura guidata, oppure è possibile utilizzare la sessione o persino salvare in una tabella del database temporaneo. Nel mio esempio completamente non testato di seguito sto usando una funzionalità di form stateful.

Ecco un esempio di ciò che fondamentalmente ho fatto per un modulo ActiveRecord. Questo va in "actionCreate":

<?php if (isset($_POST['cancel'])) {
  $this->redirect(array('home'));
} elseif (isset($_POST['step2'])) {
  $this->setPageState('step1',$_POST['Model']); // save step1 into form state
  $model=new Model('step1');
  $model->attributes = $_POST['Model'];
  if($model->validate())
    $this->render('form2',array('model'=>$model));
  else {
    $this->render('form1',array('model'=>$model));
  }
} elseif (isset($_POST['finish'])) {
  $model=new Model('finish');
  $model->attributes = $this->getPageState('step1',array()); //get the info from step 1
  $model->attributes = $_POST['Model']; // then the info from step2
  if ($model->save())
    $this->redirect(array('home'));
  else {
    $this->render('form2',array('model'=>$model));
} else { // this is the default, first time (step1)
  $model=new Model('new');
  $this->render('form1',array('model'=>$model));
} ?>

I moduli dovrebbero assomigliare a questo:

Form1:

<?php $form=$this->beginWidget('CActiveForm', array(
    'enableAjaxValidation'=>false,
    'id'=>'model-form',
    'stateful'=>true,
));
<!-- form1 fields go here -->
echo CHtml::submitButton("Cancel",array('name'=>'cancel');
echo CHtml::submitButton("On to Step 2 >",array('name'=>'step2');
$this->endWidget(); ?>

Modulo 2:

<?php $form=$this->beginWidget('CActiveForm', array(
    'enableAjaxValidation'=>false,
    'id'=>'model-form',
    'stateful'=>true,
));
<!-- form2 fields go here -->
echo CHtml::submitButton("Back to Step 1",array('name'=>'step1');
echo CHtml::submitButton("Finish",array('name'=>'finish');
$this->endWidget(); ?>

Spero che sia utile!


35
2017-08-23 21:06



Yii fornisce una funzione chiamata stati della pagina per implementare cose come una procedura guidata di modulo multi passo / multi pagina.

Diamo prima un'occhiata ai documenti Yii:

Uno stato di pagina è una variabile che è persistente tra le richieste POST della stessa pagina. Per utilizzare gli stati di pagina persistenti, i moduli devono essere stateful che vengono generati utilizzando {@link CHtml :: statefulForm}.

Quindi le forme di ogni passaggio / pagina devono essere forme stateful. Per rendere un form stateful è sufficiente impostare il CActiveForm::stateful proprietà a true quando avvii il widget ActiveForm. All'interno del tuo controller puoi ottenere e impostare gli stati della pagina con CController::getPageState() o CController::setPageState().

Quindi, queste sono le basi che funzionano abbastanza bene se l'implementazione della procedura guidata per moduli di più pagine è realizzata nello stile tradizionale senza richieste AJAX.

Se tuttavia si desidera utilizzare le chiamate AJAX per inviare i dati del passaggio e visualizzare il passaggio successivo, gli stati delle pagine di Yii non sono utilizzabili.

Perché? Tutti gli stati della pagina vengono trasportati tramite HTTP-POST all'interno di un campo di input nascosto. Il campo di input viene riempito da Yii durante la cosiddetta elaborazione di output. Inizia l'elaborazione dell'output dopo il rendering e sostituirà parti dell'output. Così La funzionalità degli stati delle pagine di Yii richiede l'elaborazione dell'output. D'altra parte le risposte AJAX possono essere danneggiate da esso perché l'elaborazione dell'output può anche aggiungere <link> o <script> tag all'inizio dell'output per caricare i file JS e CSS richiesti.

Alla fine ho implementato la mia versione di moduli stateful. Sono in grado di ottenere i miei dati di stato con la chiamata di funzione statica ActiveFormWidget::getRequestMultiStepData() ogni volta che ne ho bisogno.

Avviso: c'è un solo svantaggio nella mia implementazione: tutti i dati di stato devono essere raccolti prima che il widget del modulo venga inizializzato. Ma non ho mai avuto un problema con esso fino ad ora. Comunque qui è il codice:

class ActiveFormWidget extends CActiveForm
{
    public static $inputNameMultiStepData = '_multiStepData';

    public $multiStep = false;
    public $multiStepData = array();

    public function init()
    {
        parent::init();

        # Hidden-Fields
        if ($this->multiStep) {
            echo Html::hiddenField(static::$inputNameMultiStepData, static::encodeInputData($this->multiStepData));
        }
    }

    /**
     * Gets all multi step data sent.
     * @return array|mixed
     */
    public static function getRequestMultiStepData()
    {
        return isset($_REQUEST[static::$inputNameMultiStepData]) ? static::decodeInputData($_REQUEST[static::$inputNameMultiStepData]) : array();
    }


    /**
     * Encodes form data like Yii does for stateful forms.
     * @param $data
     * @return string
     */
    public static function encodeInputData($data)
    {
        $data = Yii::app()->getSecurityManager()->hashData(serialize($data));

        return base64_encode($data);
    }

    /**
     * Decodes form data like Yii does for stateful forms.
     * @param $data
     * @return bool|mixed
     */
    public static function decodeInputData($data)
    {
        $data = base64_decode($data);
        $data = Yii::app()->getSecurityManager()->validateData($data);
        if ($data !== false) {
            return unserialize($data);
        } else {
            return false;
        }
    }
}

4
2017-09-05 08:32