CGridView-Colonne personalizzate

Fin’ora me la sono cavata leggendo documentazioni e topic vari ma adesso devo proprio chiedervi una informazione per cui…ecco il mio primo topic…

La domanda è la seguente: come si fa a visualizzare una colonna personalizzata in una CGridView?

Mi spiego meglio. In una CGridView visualizzo i dati degli utenti del mio sistema. Tra questi c’è un campo intero chiamato ‘livello’.Quest’ultimo è una foreign key riferita ad alla tabella ‘livello_utenti’ all’interno della quale ad ogni valore intero corrisponde la descrizione testuale del livello (es. 0->guest,1->admin ecc). Ora quello che vorrei fare è visualizzare la descrizione testuale al posto del valore intero ‘livello’. Normalmente avrei fatto un semplice join ma immagino che esista un modo alternativo in yii.

Cosa mi consigliate di fare?

Intendi mostrare un valore interpretandolo e non spiattellandolo così com’è giusto?

Ammetto che userei schietto il model sfruttando il metodo relations. Sino ad ora mi è capitato solo di dover formattare un campo html.

In quel caso il mio datagrid veniva modificato in questo modo:


<?php

  $this->widget('zii.widgets.grid.CGridView', array(

    'id' => 'eventi-grid',

    'dataProvider' => $model->search(),

    'filter' => $model,

    'columns' => array(

      'id',

      'titolo',

      'abstract',

      array('name' => 'corpo', 'value' => $model->corpo, 'type' => 'html'),

      array(

        'class' => 'CButtonColumn',

      ),

    ),

  ));

?>

Come vedi, anzichè passare solo il nome di un campo, si passa un array con nome, valore e tipo. Credo che a te serva indicare il tipo.

Nella documentazione Ho trovato questo.

Così a naso forse potresti provare con


        array(            // display 'create_time' using an expression

            'name'=>'nomecampo',

            'value'=>'$altrivalori[$data->nomecampo]',

        ),

e magari prima definire il tuo array:


$altrivalori = array('admin','user');

In modo ancora più pulito, forse potresti definire queste cose dentro al file di configurazione Yii::params[‘mioarray’]. Ma mi sembra molto verboso. Non ti conviene usare una tabella con i ruoli e sfruttare Yii?

Seguendo quello che ti ha consigliato sensorario la soluzione più appetibile (per me, niubbone di Yii :P) sarebbe fare una cosa simile:




array(   

    'name'=>'livello_utenti',

    'value'=>$model::getLevel($data->livello_utente),

 ),



Non so se sia fattibile, ho sbiarciato adesso dalla doc: http://www.yiiframework.com/doc/api/1.1/CGridView

In effetti le vostre soluzioni sono interessanti. In verità un pò ci avevo pensato. Solo che non volevo passare per un array costruito ad-hoc per ogni griglia ma sfruttare il fatto che la relazione si trova comunque nel database in termini di foreign key. Forse la strada di sfruttare le relations di Yii è quella giusta ma devo fare qualche prova.

domani a mente fresca smanetto un pò e appena trovo la soluzione ve la posto

per il momento … grazie ::)

Ciao,

Ti invio un esempio di codice di come potrebbe essere:

Facciamo finta che il tuo Model per la tabella dei livelli si chiami, appunto, Livelli e che la tabella in questione abbia tue campi:

  • livello_id (corrispondente al campo livello_utente della tua tabella utenti)
  • livello_desc (descrizione)

Potrebbe essere così:


 

array(

'name'=>'livello_utenti',

'value'=>'Livelli::model()->findByPk($data->livello_id)->livello_desc',

),



Ricordati di inserire tutto il contenuto di ‘value’ (cioè Livelli::model()->findByPk($data->livello_utenti)->livello_descrizione) tra apici, così come nell’esempio.

Spero che aiuti a risolvere il problema.

Ha! Ma se hai la foreign key è tutta un’altra storia: io avevo inteso che non volevi usare le join o cose simili. Una volta definite le chiavi esterne nel model (ovvero specificando il metodo relation) puoi fare in questo modo:


<?php

  $this->widget('zii.widgets.grid.CGridView', array(

    'id' => 'moto-grid',

    'dataProvider' => $model->search(),

    'filter' => $model,

    'columns' => array(

      'id',

      'username',

      'password',

      'livello.nome',

      array(

        'class' => 'CButtonColumn',

      ),

    ),

  ));

?>

Come intuirai, livello non è un campo della tabella, ma il nome della relazione. nome, invece, è il nome del campo della tabella esterna.

Allora…ho testato sia la soluzione di sensorario che di dchan…

Quella di dchan funziona alla grande…grazie mille

Quella di sensorario non da errori ma visualizza un campo vuoto nella griglia in corrispondenza del livello. Come se gli mancasse la relation. In realtà la relation c’è eccome(a meno di errori). Questo è il codice che ho usato nel model della tabella Utenti


	

public function relations()

	{

		return array(

			'livello'=>array(self::HAS_ONE, 'Livelli', 'level_id'),

		);

	}



dove ‘livello’ è il nome del campo nella tabella Utenti, ‘Livelli’ è la tabella esterna e ‘level_id’ è il nome del campo della tabella esterna…


public function relations()

        {

                return array(

                        'livello'=>array(self::BELONGS_TO, 'Livelli', 'level_id'),

                );

        }

è corretto SE:

Nella tabella corrente il campo "level_id" è chiave esterna per la tabella livelli

PS. Ho modificato self::HAS_ONE con self::BELONGS_TO

Ho verificato. Effettivamente non c’era la definizione della foreign key. Ero convinto di averla creata ma il mio client non mi dava errori nonostante non facesse quello che gli avevo comandato. Adesso ho rifatto la cosa con MysqlGUI Tools e verificato che la chiave sia stata effettivamente creata. Il problema però permane. Ho fatto un pò di prove e ho notato che non so perché nella sintassi ‘livello.xxx’ la parte a destra del punto viene interpretata come label della colonna. Per esempio se scrivo ‘livello.pluto’ la colonna che dovrebbe essere il livello diventa ‘pluto’

Dovrebbe prendere automaticamente la label della tabella esterna. Il che, se ci pensi, è corretto.

si…solo che il dato non lo visualizza. Ho anche provato a far generare di nuovo il model a gii così ho verificato che la relation che ho creato era effettivamente corretta (con il BELONGS_TO come avevi suggerito).

Solo che ancora non funzia…

se ho capitto bene hai il campo "livello" nella tablea utente e nello steso momento hai una relazione dello stesso nome…

con $data->livello… Yii ti mosta il valore dell campo utente->livelo invece del valore della relazione…

il nome della relazione deve esere unico…

Io faccio:


array( 

  'name'=>'livello',

  'value'=>'$data->livello->nome'

)

Forse ci sono soluzioni piu’ spicce, ma io non le conosco

Ohh…finalmente è andata. Grazie mdomba.

il problema era effettivamente che il nome della relazione deve per forza di cose essere diverso dal nome del campo coinvolto nella relazione stessa.

Riporto il codice che funziona.

Questa è la relation




return array(

			'livello_fk'=>array(self::BELONGS_TO, 'Livelli', 'livello'),

		);



mentre questo è il codice della CGridView




$this->widget('zii.widgets.grid.CGridView', array(

	'id'=>'utenti-grid',

	'dataProvider'=>$model->search(),

	'filter'=>$model,

	'columns'=>array(

		'id',

		'nome',

		'cognome',

		'username',

		'livello_fk.level_description',

		array(

			'class'=>'CButtonColumn',

		),

	),

));



L’unica cosa che resta da sistemare riguarda il fatto che adesso la colonna livello è priva di campo per il filtraggio e l’ordinamento. Ma questo magari lo risolvo con calma tanto non è importante(se però qualcuno ha già la soluzione a portata di mano non la rifiuto mica ;D )

Vorrei fare un ultimo appunto visto che questa discussione la segue anche un membro dello staff. Penso di essermi perso nei meandri della griglia perché la parte della guida che descrive le relations è forse un tantino ambigua. Mi spiego meglio. Normalmente quando si crea una relazione tra tabelle riguardo una foreign key si specificano sia le tabelle che i campi coinvolti. In questo caso ad esempio la tabella utenti aveva un campo ‘livello’ che corrispondeva ad una chiave primaria della tabella ‘livelli’ sita nel campo ‘level_id’. Il mio errore è stato quello di voler specificare nella relazione quale fosse il campo specifico della tabella esterna(level_id).

In realtà adesso credo di aver capito che la relazione di fatto specifica solo che un certo campo ha una relazione con una tabella esterna, senza preoccuparsi di specificare qual’è effettivamente il campo della tabella esterna. Quest’ultima cosa è infatti intrinseca nella struttura relazionale del DB.

Ovviamente correggetemi subito se ho scritto delle cavolate…

Mmmm non ho tempo di rileggere bene che cosa avevo scritto a suo tempo, ma mi ero fatto sta piccola guida. Guarda un po’ se c’è quello che ti serve nell’allegato.

Ho guardato la soluzione che avete proposto con le relations e effettivamente è molto più pulita e funzionale rispetto a quella che avevo proposto io.

Infatti ho preso spunto dai vostri suggerimenti per modificare un’implementazione che ho fatto sulla mia prima (quasi ultimata) implementazione con Yii.

Grazie ancora a tutti per i vostri preziosi suggerimenti anche se… più leggo i vostri post e più mi rendo conto che ho ancora da studiare… :-[