[Risolto] Validazione + Models Contemporaneamente

Ciao ragazzi,

sto cercando di validare un form con + model al suo interno…

mi spiego meglio:

ammettiamo di avere un form che associ + model del tipo:

  • User
  • Localita
  • sportPreferiti

Ovviamente sono 2 tabelle relazionate a quella principale che è user tramite due tabelle associative, tipo:

User UserLocalitaLocalita

User UserSportPreferitiSport

Quindi stiamo parlando di 5 tabelle.

cmq il fatto è + semplice della spiegazione:

come è possibile validare tutti i models relazionati dentro lo stesso form? perchè "User" si valida in modo semplice ma gli altri?..e se per caso "Localita" lo vorrei impostare obbligatorio mentre "SportPreferiti" no?

esempio: se nella compilazione uno mi inserisce i dati dell’utente e BASTA, io vorrei comunicargli tramite il sistema di errors che deve per forza compilare almeno anche le info riguardanti la “Localita”, ma come?

spero di essermi spiegato :D

Grazie in anticipo!

Io faccio in questa maniera:

Nel model principale preparo delle variabili per salvare i model secondari:


public User extends CActiveRecord{

  public $localita;

  public $sport;

A questo punto nel model puoi mettere delle custom rules che gestisci con una funzione, in questa funzione puoi controllare anche le proprieta’ degli altri modelli.

Questo serve se un utente carica delle foto, e vuoi contorllare che carichi almeno una foto.

Ma il tuo caso e’ piu’ semplice, ti basta mettere delle rules in localita’ e validare tutto, nella actionUpdate:




  $model->attributes= $_POST['User'];

  $localita->attributes= $_POST['Localita'];


  $valid= $model->validate();

  $valid= $localita->validate() && $valid;

  if ($valid)

  {

     Salva tutto!

  }



Grazie della risposta!

…non appena possibile posterò il risultato dell’operazione,

thx.

Ciao a tutti,

volevo postare la mia "soluzione" a riguardo, e magari ricevere consigli e/o critiche per farlo in modo differente etc etc…

cmq, seguendo le indicazioni di Zaccaria, ho messo mani nel "model_principale" + "controller" + "_form.php":

il model principale che si achiama "Aree":




class Aree extends LinceActiveRecord

{

	//*** questo è l'attributo che inserisco per servirmene in futuro nel controller...

	public $componentiApplicazioni;


	...


	public function rules()

	{

        	...

			//*** aggiungo nelle rules il nome del "campo" che voglio validare che in questo caso è praticamente

        	//*** il nome dell'attributo appena inserito, la funzione che se ne occupa è stata createa da me e sta all'interno del model.

			array('componentiApplicazioni','checkComponentiApplicazioni'),

			...

	}


	


	public function checkComponentiApplicazioni(){

		$obj = $this->componentiApplicazioni;		

		if( LinceFunctions::emptyAttributes($obj) ){

			//*** se è vuoto stampo un errore di avviso che l'input non può essere vuoto

			$this->addError('componentiApplicazioni',"Deve essere scelto almeno uno dei seguenti campi");

		}else{

			//*** se è pieno procedo alla validazione dell'oggetto

			//*** tramite le !!proprie rules!!

			if(!$obj->validate()){

				foreach ($obj->getErrors() as $campo=>$erroriDelCampo){

					$msg = implode( '<br />', $erroriDelCampo );

				}

				$this->addError( 'componentiApplicazioni', $msg );

			}

		}

	}



pasisamo al Controller "AreeController":




...

	public function actionCreate()

	{

		$model=new Aree;

		$valida=false;

		if( isset($_POST['ComponentiApplicazioni']) ){

			//*** sull'attributo creato nel model Aree gli associo un oggetto di tipo "ComponentiApplicazioni"

        	$model->componentiApplicazioni = new ComponentiApplicazioni();

        	//*** poi gli inserisco i dati del post...

			$model->componentiApplicazioni->attributes = $_POST['ComponentiApplicazioni'];

         	//*** poi valido, ma attenzione alla forma, perchè validando $model(che è il model principale "Aree")

        	//*** metto in gioco l'azione delle rules di Aree, ovvero proprio dell'istruzione che ho inserito io precedentemente

        	//*** per validare l'attributo "componentiApplicazioni", in questo modo se la validazione appena fatta è negativa

        	//*** stampa l'errore presente all'interno della funzione custom "checkComponentiApplicazioni"

			$valida = $model->validate();

		}

		

		// Uncomment the following line if AJAX validation is needed

		// $this->performAjaxValidation($model);


		if(isset($_POST['Aree']))

		{

			$model->attributes=$_POST['Aree'];

			if($model->validate() && $valida ){

				if($model->save())

					$this->redirect(array('view','id'=>$model->id_area));

			}

		}


		$this->render('create',array(

			'model'=>$model,

		));

	}

...



in fine nel form"aree/_form.php":




	<!-- inserisco questo elemento nel form *** -->

	<div class="row">

    	<!-- creo l'oggetto -->

		<?php $compAppl = new ComponentiApplicazioni;?>

    	<!-- creo il label e lo associo proprio all'attributo creato precedentemente nel model principale "Aree" -->

		<?php echo $form->labelEx($model, 'componentiApplicazioni'); ?>

    	<!-- di seguito una lista di checkBox personalizzata, poco importante ai fini di questo post(è semplicemente una lista di checkBox) -->

		<?php echo $form->linceCheckBoxList($compAppl, 'fk_id_componenti',Componenti::model(), 'id_componenti', 'desc_nome'); ?>	  

    	<!-- infine imposta l'html per "ospitare" l'eventuale messaggio di errore, sempre relativo all'attributo, come si può ben vedere -->

		<?php echo $form->error($model,'componentiApplicazioni'); ?>

	</div>

	<!-- /TEST *** -->



praticamente, con l’incrocio di questi 3 elementi riesco a fare la validazione col relativo print dei messaggi a schermo di + models associati nello stesso form.

avete consigli su come "accorciare" la cosa se possibile?

Grazie!

ciao.

Prova a fare in questa maniera:


        public function actionCreate()

        {

                $model=new Aree;

                $model->componentiApplicazioni = new ComponentiApplicazioni();

                


                if(isset($_POST['Aree']) &&  isset($_POST['ComponentiApplicazioni']))

                {

                        $model->attributes=$_POST['Aree'];

                        $model->componentiApplicazioni->attributes = $_POST['ComponentiApplicazioni'];

                        $valida = $model->validate();

                        $valida = $model->validate() && $valida;

                        if($valida ){

                           $model->save();

                           $model->componentiApplicazioni->save();

                           $this->redirect(array('view','id'=>$model->id_area));

                        }

                }


                $this->render('create',array(

                        'model'=>$model,

                ));

        }

In questa maniera non devi fare nulla nel model ( a parte create la proprieta’ componentiApplicazioni).

Ogni modello valida le sue cose, e si tiene i suoi errori. La validazione la fai nel componentiApplicazioni e gli errori li puoi agganciare ad un attributo fittizio che ti serve solo per generare la label e mostrare gli errori

La error summary la generi come


$form->errorSummary($model, $model->componentApplicazioni);

Sei riuscito a risolvere? Serve ancora aiuto?

Devo testare il codice scritto…ma siccome lo sto facendo a lavoro…non posso aggiornarvi prima di lunedí/martedí…

Si anche il tuo codice ovviamente funziona, ma io avrei una necessità del tipo:

"Controllare nel model principale (Aree) che il model a lui associato (ComponentiApplicazioni) non sia lasciato vuoto, perchè se sì allora ti stampo il messaggio <non è possibile lasciare vuoto un componente dell’applicazione> senza usare il validate() dell’oggetto ComponenteApplicazione ma facendomi una funzione che mi testi semplicemente se ci sono i dati richiesti (vedi checkComponentiApplicazioni).

nel qual caso invece sia pieno, allora passo alla validazione specifica dell’oggetto ComponentiApplicazioni->validate() e lì anche controllo se ci sono valori scorretti allora ti stampo il mesaggio di errore relativo."

eheh, non sò se mi sono spiegato bene :o

riassumendo: 1step, controllo se l’utente ha scritto il model, 2step nell’eventualità sia scritto ne controllo la correttezza…

ecco perchè avevo aggiunto la funzione checkComponentiApplicazioni …credo che sia la strada giusta no?

Grazie cmq per l’ineressamento,

sensorario se vuoi puoi anche chiudere il post perchè cmq credo di aver capito la logica del flusso, e vi ringrazio ancora una volta! :)