Ricercare per una chiave esterna?

Ho fatto diversi tentativi e nessuno è andato a buon fine. Ho una tabella che "attinge" da tabelle esterne. Quando metto in un datagrid dei campi esterni, non compare più il campo di ricerca. Vorrei, invece, che rimanesse. Come posso farlo? Non ho trovato link su yii, forse non ho cercato bene. Sono anche sicuro di aver letto qualche cosa del genere in questo forum. Chi mi sa aiutare a cercarlo?

Per ricercare su campi esterni devi:

aggiungere le proprieta’ al model, per poter raccogliere i dati

marcare queste proprieta’ come safe on search nelle rules

aggiungere i criteria nella funzione search (sia with->toghether che le condition)

Una volta fatto questo, puoi rimettere le textbox nel datagrid con la proprita’ filter di cgridView.

Non conosco la sintassi corretta del punto "aggiungere i criteria nella funzione search (sia with->toghether che le condition)" Per il resto ho fatto tutto. Mi potresti dare un ultimo piccolo help?


      public function search() {

          // Warning: Please modify the following code to remove attributes that

          // should not be searched.


          $criteria = new CDbCriteria;


          $criteria->compare('id', $this->id);

          $criteria->compare('nome', $this->nome, true);

          $criteria->compare('citta', $this->citta, true);

          $criteria->condition = 'cittadina = citta';


          return new CActiveDataProvider(get_class($this), array(

            'criteria' => $criteria,

          ));

      }

Ho creato una tabella paesi(id,nome,citta) citta corrisponde all’id di citta(id,nome).

Il with come lo metto? Scusami ma ho un lapsus

Non demordo: ora funziona (nel senso che no mi da errori… devo solo mettere la textbox dentro al CDataGrid


      public function search() {

          // Warning: Please modify the following code to remove attributes that

          // should not be searched.


          $criteria = new CDbCriteria;


          $criteria->compare('id', $this->id);

          $criteria->compare('nome', $this->nome, true);

          $criteria->condition = 'cittadina.id = citta';

          $criteria->with = array('cittadina');


          return new CActiveDataProvider(get_class($this), array(

            'criteria' => $criteria,

          ));

      }

Ce l’ho fatta!!!

(ho trovato un post di qualche tempo fa di zaccaria e mdomba nel forum inglese)

Così ho saputo correggere il mio codice in questo modo:

MODEL:

nel model si deve prima creare la relazione e poi aggiungerla nelle regole


      public function rules() {

          return array(

            array('nome, citta', 'required'),

            array('citta', 'numerical', 'integerOnly' => true),

            array('nome', 'length', 'max' => 50),

            array('id, nome, citta, cittadina', 'safe', 'on' => 'search'),

          );

      }


      /**

       * @return array relational rules.

       */

      public function relations() {

          // NOTE: you may need to adjust the relation name and the related

          // class name for the relations automatically generated below.

          return array(

            'cittadina' => array(self::BELONGS_TO, 'Citta', 'citta'),

          );

      }

VIEW:

Nel CGridView bisogna aggiungere un array ed indicare il nome della relazione, il filtro da usare ed il valore.


<?php

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

    'id' => 'paesi-grid',

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

    'filter' => $model,

    'columns' => array(

      'id',

      'nome',

      array(

        'name' => 'cittadina',

        'filter' => CHtml::activeTextField($model, 'cittadina'),

        'value' => '$data->cittadina->nome',

      ),

      array(

        'class' => 'CButtonColumn',

      ),

    ),

  ));

?>

CONTROLLER:

Infine nel controller bisogna fare si che la ricerca vada a ficcare il naso nella tabella esterna.


      public function search() {


          $criteria = new CDbCriteria;


          $criteria->compare('nome', $this->nome, true);

          $criteria->compare('cittadina.nome', $this->cittadina, true);

          $criteria->join = 'join citta on citta.id = t.citta';

          $criteria->with = array('cittadina');


          return new CActiveDataProvider(get_class($this), array(

            'criteria' => $criteria,

          ));

      }

Per completare questo post, ci aggiungo anche il Dump del mio database nel caso qualcuno volesse provare questo esempio per conto proprio come ho fatto io:





CREATE TABLE IF NOT EXISTS `citta` (

  `id` int(11) NOT NULL AUTO_INCREMENT,

  `nome` varchar(50) NOT NULL,

  PRIMARY KEY (`id`)

) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;


INSERT INTO `citta` (`id`, `nome`) VALUES

(1, 'Cesena'),

(2, 'Roma');


CREATE TABLE IF NOT EXISTS `paesi` (

  `id` int(11) NOT NULL AUTO_INCREMENT,

  `nome` varchar(50) NOT NULL,

  `citta` int(11) NOT NULL,

  PRIMARY KEY (`id`)

) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;


INSERT INTO `paesi` (`id`, `nome`, `citta`) VALUES

(1, 'San Carlo', 1),

(2, 'San Vittore', 1),

(3, 'Trastevere', 2);




TESTATO E FUNZIONANTE!

Problema! citta.nome e paesi.nome entrano in conflitto.




          $criteria->compare('nome', $this->nome, true);

          $criteria->compare('cittadina.nome', $this->cittadina, true);

Se cerco per città funziona tutto correttamente. Se però cerco per nome ottengo un errorone brutto brutto =(. Allego l’errore e prego.

Per inciso: l’errore sta nel fatto che la query è del tipo select paesi.nome, citta.nome. Trovandosi con due nomi uguale va in errore. Suppongo sia lo stesso problema riscontrato su chive che ho segnalato come bug e che dovrebbe essere corretto nella prossima versione.

semplicemente l’errore viene dato perchè nel where gli dici di controllare nome, il problema sta che in entrambe le tabelle c’è una colonna nome, quindi il dato è ambiguo, quindi devi specificare quello di quale tabella

Che poi è quello che ho scritto io. Ho due campi nome. Come faccio a dare loro un alias?

yii in teoria lo fa in automatico.

nel metodo relations del model assegni un alias a ciascuna relazione (di solito io uso relNomeModel per evitare possibili eventuali conflitti con nomi di colonne, quindi se ho una tabella user che ha relazioni con una tabella groups chiamo la relazione relGroups)

se stai usando CDbCriteria usa la dot notation quando chiami il nome del campo (relGroups.nome)

se devi chiamare il dato della tabella originale yii usa come alias t (o almeno così faceva nella versione 1.1.5 quando stavo impazzendo per capire che stava facendo)

se qualcosa non ti torna o hai dubbi fai mostrare al debug le query così vedi quali alias yii genera in automatico.

inoltre usare un alias tipo relNomeModel rende più semplice la lettura quando estrai i dati dall’oggetto.

se ad esempio vedi una cosa del tipo $user->relGroup->name capisci subito senza dovertelo ricordare che il dato name che stai estraendo si trova in realtà in un altra tabella.

Come faccio a mostrare al debug le query così vedo quali alias yii ha generato in automatico?

Ho risolto:


      public function search() {

          // Warning: Please modify the following code to remove attributes that

          // should not be searched.


          $criteria = new CDbCriteria;


          $criteria->compare('t.nome', $this->nome, true);

          $criteria->compare('cittadina.nome', $this->cittadina, true);

          $criteria->join = 'join citta on citta.id = t.citta';

          $criteria->with = array('cittadina');


          return new CActiveDataProvider(get_class($this), array(

            'criteria' => $criteria,

          ));

      }

ovvero:




          $criteria->compare('t.nome', $this->nome, true);

L’informazione di nickcv, quella di usare la dot notation era corretta solo che non specificava dove e come andava usata. Spero non abbia nulla in contrario se riposto la soluzione.

le impostazioni del debug sono nel file config della tua applicazione yii, comunque non c’è bisogno al momento, riguardando la tua schermata d’errore si può benissimo leggere la query.

come giustamente ricordavo l’alias della prima tabella è t mentre quella della seconda tabella in questo caso è citta

scusa la risposta frettolosa ma sto fuggendo per arrivare in ufficio ^^

nessun problema sensorario :P

è che a volte sono un pò di fretta e mi rendo conto che do per scontate alcune conoscenze pregresse ^^

sono contento comunque che hai risolto!