Validazione Custom e Dependent di più campi

salve a tutti, ho un problema che non so proprio come risolvere.

Devo validare più campi in maniera dipendente, esempio se il campo vendi_a = ‘privati’ allora deve essere compilati determinati campi altrimenti se è settato su ‘azienda’ devono essere presenti i relativi prezzi per l’azienda.

Il tutto per una lista abbastanza lunga di campi.

Ho provato la seguente estensione yii-conditional-validator ma non funziona.

L’ideale sarebbe per me poter scrivere un metodo validatore custom all’interno del model, ma guardando le specifiche, ho visto che tale procedura è applicabile ad un singolo attributo per volta.

Qualcuno sa come aiutarmi?

Grazie infinite

Potresti scegliere PRIMA il tipo di form da visualizzare e poi visualizzare quello corretto una volta stabilito se è destinato ad un privato o ad una azienda?

Ecco: potresti far diventare astratta la classe del tuo attuale model ed estenderla in due sottoclassi dove ridefinisci solo la validazione dei campi. Che ne pensi?

Putroppo è un progetto che sto sviluppando per un cliente, per una serie di motivi, la pagina di inserimento del prodotto deve venire in questa maniera. Il mio vincolo è questo.

Inoltre non è l’unico campo sul quale devo effettuare una validazione per cosi dire “dependent”.

Come ultima strada, utilizzerò una validazione javascript scritta totalmente a mano.

Però mi sembra strano che questo ottimo framework non incorpori già da se meccanismi di questo tipo, che mi sembra capire dalle ricerche effettuate, siano esigenze abbastanza comuni.

Mi è stato suggerito di scrivere un codice del genere:




//rules

array('prezzo_privatti', 'validatePrezzoPrivatti');


public function validatePrezzoPrivatti($attribute, $params)

{

    //logic:

    if ($this->vendi_a == 'privatti' && empty($this->$attribute)) {

        $this->addError($attribute, 'You must define prezzo when vendi_a is privatti'); 

        //or some message like

    }

}



è possibile scrivere invece un codice come nell’esempio seguente? (non badate alla sintassi etc etc è solo una specie di pseudo codice)




//rules

array('prezzo_privatti, prezzo_azienda, offerta_privati, offerta_azienda, altri_campi', 'validatePrezzoPrivatti');


public function validatePrezzoPrivatti($attribute, $params)

{

    switch($attribute){

        case "prezzo_privati":

          if ($this->vendi_a == 'privatti' && empty($this->$attribute)) {

          $this->addError($attribute, 'You must define prezzo when vendi_a is privatti'); 

         //or some message like

         break;

        case "altro_campo":

            codice

            break;

    }

}



O comunque altri suggerimenti sono ovviamente ben accetti

Potresti definirmi "per una serie di motivi"?

Fa parte dell’analisi dei requisiti inviatami dal cliente.

Tuttavia il problema è un’altro, ho trovato il meccanismo per raggiungere il mio scopo ed è utilizzare la classe indicata all’inizio del post, che al contrario di quanto ho affermato precedentemente, funziona bene.

Ecco il link yii-conditional-validator

La questione è un’altra a questo punto: ho capito (purtroppo solo ora), che quando l’opzione “enableClientValidation” è abilitata, yii scrive per me tutto il codice javascript solo per quello che riguarda le rules “standard” e non per i validatori custom.

Quando come validatore invece si utilizza una classe o un metodo custom, le validazioni avvengono solo e soltanto dopo che tutti i controlli client-side hanno dato true.

C’è un metodo per poter effettuare queste validazioni custom lato client, senza dover scrivere a mano tutto il codice javascript necessario?

Ho dato un’occhiata anche a questo post (custom-validation-rule-ClientSide) ma ancora una volta il metodo funge per un solo attributo.

Grazie :)

Domanda: non puoi implementare tu, via javascript il controllo su più campi?

Risposta:

Certo che posso ma la mia richiesta è un’altra come puoi ben vedere, leggi bene il post :slight_smile:

la volevo lasciare come ultima strada.

Sarebbe stato davvero utile un meccanismo per generare validazioni client side custom, attraverso apposite regole definite dentro il metodo rules nel model.

Il meccanismo a dire il vero esiste già, grazie al contributo dell’utente SIDTJ

ma è solo per le validazioni server side.

Grazie lo stesso comunque

Ho letto ho letto =). Solo che sono abituato ad usare una soluzione, anche se non migliore, fino a quando non posso migliorare le cose. La mia regola è "prima implemento una nuova feature, poi la ottimizzo". Nel tuo caso, mi sembra di capire che non hai adottato soluzioni quando avresti potuto comunque ottenere un risultato (anche se migliorabile).

Forse puoi fare validazioni su più campi LATO SERVER anche con ajax.

Se noti nei controller CRUD generati di default da YII c’è questo metodo:




	protected function performAjaxValidation($model) {

		if (isset($_POST['ajax']) && $_POST['ajax'] === 'tmpl-template-form') {

			echo CActiveForm::validate($model);

			Yii::app()->end();

		}

	}



Questo metodo sfrutta il metodo validate del model che è questo:




	public static function validate($models, $attributes=null, $loadInput=true)

	{

		$result=array();

		if(!is_array($models))

			$models=array($models);

		foreach($models as $model)

		{

			if($loadInput && isset($_POST[get_class($model)]))

				$model->attributes=$_POST[get_class($model)];

			$model->validate($attributes);

			foreach($model->getErrors() as $attribute=>$errors)

				$result[CHtml::activeId($model,$attribute)]=$errors;

		}

		return function_exists('json_encode') ? json_encode($result) : CJSON::encode($result);

	}



Un’idea sarebbe modificare quest’ultimo metodo aggiungendoci una validazione multicampo e appiccicarlo al controller così:





	protected function performAjaxValidation($model) {

		if (isset($_POST['ajax']) && $_POST['ajax'] === 'tmpl-template-form') {

			echo self::myValidate($model);

			Yii::app()->end();

		}

	}<br class="Apple-interchange-newline">

	public static function myValidate($models, $attributes=null, $loadInput=true)

	{

		$result=array();

		if(!is_array($models))

			$models=array($models);

		foreach($models as $model)

		{

			if($loadInput && isset($_POST[get_class($model)]))

				$model->attributes=$_POST[get_class($model)];

			$model->validate($attributes);

			foreach($model->getErrors() as $attribute=>$errors)

				$result[CHtml::activeId($model,$attribute)]=$errors;

		}

		//validazione a più campi

		if( !....... ){

			$result['general_errors']="errore di validazione multicampo"

		}

		return function_exists('json_encode') ? json_encode($result) : CJSON::encode($result);

	}




Poi nel model metti un’attributo general_errors e nel form aggiungi




<?php echo $form->error($model, 'general_errors ', array('class' => 'clearfix error')); ?>



In questo modo dovresti risolvere LATO SERVER… non l’ho mai provato però :)

Guarda com’è il metodo per creare le validazioni lato client, magari lo puoi adattare come ho fatto per la parte server.

In ogni caso le validazioni lato client sono inutilizzabili se devi condizionare la validazione con informazioni nel database… se poi ci aggiungi il problema che attivando le validazioni lato client non vengono eseguite quelle lato server … in form complessi di questo tipo la validazione javascript è inutile e inutilizzabile… per non parlare del fatto che un form sicuro alla fine la validazione lato server la deve sempre fare a prescindere dai controlli javascript!

L ext conditional-validator sembra ottima per ciò che devi fare tu. Ma se vuoi una validazione client side potresti adoperarti con jquery, altrimenti propongo un’‘altra soluzione: fai scegliere all’ utente tramite un menu a tendina se è azienda o privato ed invii questa informazione in ajax, dall’action a seconda della selezione invii il model corretto.

Grazie a tutti per il contributo, l’idea suggerita da proid mi sembra la migliore per il mio scopo.

Tuttavia ho già risolto in questa maniera per il momento:

ho inserito tutte le validazioni standard dentro il metodo rules() e questo ha generato codice javascript per validazioni client-side per verificare che i campi necessari siano riempiti.

Fino a che tutti i campi non sono riempiti ogni clic sul tasto submit non permette il refresh della pagina senza aver fissato gli errori.

Nel metodo rules() sono presenti inoltre validazioni che richiedono l’interazione con il server, ad esempio i vincoli unique (che in teoria dovrebbero avvenire sempre clientside con chiamate ajax)

Tali controlli però si attivano solo dopo che tutti i controlli clientside sono superati, la pagina viene ricaricata e vengono mostrati i nuovi errori. In questa fase vengono verificati anche i vincoli creati con l’estensione sopra menzionata. Tuttavia ho ancora dei dubbi su alcune cose.

Domanda 1: ho abilitato la validazione ajax sugli eventi submit, type e change, però il vincolo unique viene verificato solo dopo aver superato i controlli clientside e comunque sempre dopo che la pagina si è ricaricata. E’ normale? Credo di no, questo mi succede solo con questo form. Con altri form funziona tutto bene senza che la pagina si ricarichi.

Domanda 2: sempre sullo stesso form, il campo "accetta_condizioni" (boolean nel db e checkbox sulle pagine)

se lo imposto come required nel model , anche se è cliccato, mi risponde sempre che è vuoto e che ha bisogno di un valore.

Lo stesso codice in un altro form, funziona bene.

Può dipendere dall’ordine delle rules?