Ma come si scambiano dati tra controller e modello?

Oltre a capire come funziona questo framework, mi piacerebbe anche capire come programmare decentemente.

Ora io mi sono avvicinato a Yii perchè ho letto che l’MVC è implementato in maniera magistrale.

Ma non riesco ad usarlo, sono bloccato nel passaggio dati tra controller e modello.

Non ho capito come si faccia.

Esempio pratico. Prendiamo un controller per la gestione della registrazione di un nuovo utente:





class IscrizioneController extends Controller

{

	public function actionIndex()

	{

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

		{

			$obj = new NewUser();

			$errore = $obj->AddUser(); //0 ho salvato con successo; >= 1 errore di qualcosa

		} else $errore = -1; //nessun errore




            $this->render('index', array('content'=>$errore)); //visualizzo il form, eventualmente con l'errore rilevato

	}

}



bene il passaggio tra controller e view è una figata: basta passare l’array nella funzione render, e dall’altra parte (nella view) avrò tutte le variabili che mi servono. Fantastico!

Invece per il modello, non ho capito come si lavori.

Leggo dalle best practice:

i model dovrebbero contenere la logica di funzionamento (es. regole di validazione)

per assicurare la piena corrispondenza dei dati alle esigenze di progetto;

In generale i model non dovrebbero contenere logica che abbia a che fare

direttamente con gli utenti finali. Più in dettaglio, i model:

  • non dovrebbero utilizzare $_GET, $_POST o varaibili simili che sono

direttamente legate alle richieste dell’utente finale.

Allora io mi e vi domando, ma come faccio ad implementare le regole di validazione se non dovrebbero utilizzare $_get e $_post ?

Per meglio documentare il mio dramma, riporto un pezzo di model che ho mal implementato:





class NewUser extends User

{


	public function AddUser()

	{

		return $this->ErrorReport(); //ritorna 0 se ha salvato ok ; 1 se IsEmptyField ; 2 se la mail è errata    

	}


	protected function IsEmptyField()

	{

		if(empty($_POST['username']) OR empty($_POST['email']) OR empty($_POST['password']))

		{

			return TRUE;

		}

		else

		{

			return FALSE;

		}

	}



Come potete vedere, il modello non rispetterebbe le best practice perché contiene dei $_post. Come faccio ad implementare la logica di controllo?

[font="arial, verdana, tahoma, sans-serif"]

[/font]

[font="arial, verdana, tahoma, sans-serif"]Esiste un modo di passare i dati tra controller e model, come lo si fa tra controller e view? Voi come lavorate? Ogni spunto, idea è ben accetto.[/font]

Io, in genere, lavoro per step incrementali. Per comodità uso get e post direttamente nella view. Ma successivamente "sposto" tutto nel controller. Esempio:

Step 1 - tutto nella view




    <?php if(isset($_GET['qualcosa'])) : ?>

        <?php echo $_GET['qualcosa']; ?>

    <?php endif; ?>



Step 2 - la view come la vorrei




    <?php if($condizione) : ?>

        <?php echo $qualcosa; ?>

    <?php endif; ?>



Step 3 - controller




    function actionQualcosa () {

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

            'condizione' => isset($_GET['qualcosa']),

            'qualcosa' => $_GET['qualcosa'],

        ));

    }



PS. questo è solo un esempio. se get non è stato settato viene generato un errore. Il prossimo dovrebbe essere un codice più completo:




    function actionQualcosa () {

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

            'condizione' => isset($_GET['qualcosa']),

            'qualcosa' => isset($_GET['qualcosa']) ? $_GET['qualcosa'] : false,

        ));

    }



o ancora meglio:




    function actionQualcosa () {

        $isset = isset($_GET['qualcosa']);

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

            'condizione' => $isset,

            'qualcosa' => $isset ? $_GET['qualcosa'] : false,

        ));

    }



in generale, comunque, prima faccio le cose nella view, e poi mi assicuro che il codice sia corretto.

Quindi anche tu non ti attieni alle best practice, che vorrebbero che i controlli venissero implementati nel model.

Oppure sono io che mi sono spiegato male…

Supponi che stai sviluppando la parte di codice inerente la registrazione di un utente

e devi controllare prima di salvare, che tutti i campi del form siano valorizzati correttamente.

Dove vai a scrivere questo pezzo di codice? Nel controller o nel model?

E come fai?

Aggiungo un link alla documentazione che spiega l’arcano:

http://www.yiiframework.com/doc/guide/1.1/en/database.ar#data-validation

E devo dire che questo yii ogni volta riesce a stupirmi. L’hanno pensato proprio bene.

A questo punto sarebbe bello vedere uno spezzone di codice che mostri come si implementi praticamente quanto spiegato nel link.

le domande di Gianfranco sono molto importanti.

I model come sappiamo si preoccupano della logica del MVC.

se ad esempio sono nel mio bellissimo AnagraficaController, e devo recuperare una $listaposizione da passare al mio view non devo fare altro chè creare nel model Anagrafica una public function che restituisce con return i dati desidedati.

Naturalmente, nel controller prima di richiamare


		$listaposizione=$model->listaposizione(); 

è necessario creare una var


		$model=new Anagrafica; 

Infine bisogna fare un render come sai.

se vuoi richiamarla dal view userai sempre


$model->listaposizione();

naturalmente non è necessario che fai il render dal controller.

Spero di essere stato chiaro e soprattutto corretto. ;)

Ho fatto un esempio sbagliato. Un if nella view può ingannare. A dire il vero non ci andrebbe proprio. Se guardi bene un "create" dovresti capire bene la logica MVC di yii. La view serve per mostrare un record o un form. Non deve sapere che valori hanno _POST o _GET. Il controller dice, "io salvo dei dati o mostro dei template". Ma a gestire i dati o a gestire i template ci devono pensare da soli ed in totale autonomia Model e View. Diciamo che nel controller fai un merge.




    public function actionCreate() {


        $model = new Qualcosa;


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

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

            if ($model->save())

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

        }


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

            'model' => $model,

        ));


    }



E fin qui ci sono…

Lato controller ok,

ma lato model, come si implementano queste regole di validazione?

Magari per voi è scontato, ma per noi principianti non è così.

Finora ho capito che tramite gii creo la classe associata alla tabella.

e che dal controller nel momento in cui invoco il metodo save, vengono verificate queste validation rules.

ok, ma praticamente come le scrivo queste regole di validazione?

Sarebbe possibile vedere del codice?

forse ho capito male, ma sembra tu stia confondendo i vari componenti dell’MVC: il controller riceve le informazioni, le incapsula creando il model (ad esempio User) ed a questo punto chiama l’operazione save. Questa operazione richiama le regole di validazione che hai definito nel model (vedi http://www.yiiframework.com/doc/guide/1.1/en/form.model#declaring-validation-rules ) e se tutto è ok ritorna true altrimenti false per qualche tipo di errore.

Quindi non utilizzi $_get e $_post nel model perchè ci pensa l controller a passare i dati necessari al model.

spero di aver risposto hai tuoi dubbi

Il codice della validazione è scritto dentro al CActiveRecord. Nel model devi solo indicare i campi e le regole. Per farlo, devi semplicemente definire l’array del metodo rules del tuo model.

Supponiamo che tu stia lavorando ad un modulo per l’inserimento delle immagini e voglia dire che un certo campo è un campo di tipo immagine. Nel model dovresti scrivere:




        public function rules()

        {

                return array(

                        array('image', 'required'),

                        array('image', 'file', 'allowEmpty' => FALSE, 'types' => 'gif, jpg, png'),

                        array('id, image', 'safe', 'on'=>'search'),

                );

        }



Lo so sono paranoico, ma secondo me riuscire a programmare bene, significa anche essere in grado di capire se il pezzo di codice che s sta sviluppando, dev’essere inserito nel model, nel controller o nella view.

A tal proposito segnalo un’estensione che mi ha confuso ulteriormente le idee:

http://www.yiiframework.com/extension/messagestack/

chissà che riesca a confonderle anche agli esperti del forum