Yii::app()->user->quelloCheVoglioIo()

Vi spiego la situazione. All’interno di un Controller ho il seguente codice:




$booPossoAttaccare = Yii::app()

                        ->db

                        ->createCommand()

                        ->select('*')

                        ->from('Costruzioni')

                        ->join('SbloccoAzione', 'SbloccoAzione.idedificio = Costruzioni.idedificio')

                        ->join('Azioni', 'Azioni.id = SbloccoAzione.idazione')

                        ->where('Costruzioni.idutente=' . Yii::app()->user->id . ' and Azioni.nome="Attacca il nemico"')

                        ->query()

                        ->count() == 0 ? false : true;



Il codice qui sopra, mi sembrava molto ingombrante, quindi ho pensate che sarebbe interessante poterlo scrivere in questo modo:


Yii::app()->user->possoAttaccare()

Al che l’ho scritto davvero senza implementare nulla e mi sono beccato questa eccezzione.


CWebUser does not have a method named "possoAttaccare". (/Library/WebServer/yii/framework/base/CComponent.php:246)

Siccome CWebUser non ha quel metodo sapete che cosa faccio?

Mi creo una mia classe che estende CWebUser in questo modo:




class WebUSer extends CWebUser {


    public function possoAttaccare() {

        return Yii::app()

                        ->db

                        ->createCommand()

                        ->select('*')

                        ->from('Costruzioni')

                        ->join('SbloccoAzione', 'SbloccoAzione.idedificio = Costruzioni.idedificio')

                        ->join('Azioni', 'Azioni.id = SbloccoAzione.idazione')

                        ->where('Costruzioni.idutente=' . Yii::app()->user->id . ' and Azioni.nome="Attacca il nemico"')

                        ->query()

                        ->count() == 0 ? false : true;

    }


}



E poi dico ad yii che deve usare la mia classe come componente user (aggiungendo ‘class’ => ‘WebUser’,). In un config standard ‘class’ è omesso e di default è CWebUser se non sbaglio.




    'components' => array(

        ...

        'user' => array(

            'class' => 'WebUser',

            'allowAutoLogin' => true,

        ),



Morale della favola? Se yii non lo fa… estendiamolo. E’ semplice. E’ facile. E noi gli vogliamo sempre più bene. Ho scritto questo post perché l’esempio mi sembrava abbastanza semplice per dire come si estende CWebUSer ma in generale per dire che quando yii ci dice che non si può fare una cosa con una determinata classe, noi possiamo estenderla al volo. Ovviamente quello che vi ho mostrato non è il solo modo però mi piaceva.

Spero possa essere utile =).

Bell post semplice e utile se il metodo aggiunto serve in tutta la applicazione

To corrego soltanto su questa line… Yii non dice che non si puo… Yii dice che “per addesso” non lo sa ;)

Professore… io non ho capito 2 cose:

  1. come dice mdomba, utile se il metodo aggiunto serve in tutta l’applicazione.

Ma se ad esempio devo usare db, non posso scrivere in tutta l’applicazione direttamente Yii::app()->db-> ? Dove sta il vantaggio nell’estensione?

  1. sempre proseguendo l’esempio, una volta esteso, come dovrei accedere a db ?
  1. Il vantaggio sta nel fatto che non devo scrivere del codice più di una volta: estendo il componente user e da li in poi, ovunque voglia recuperare un determinato dato … scrivo Yii::app()->dammiQuelDato(). Il vantaggio è che la query sarà solo in un luogo.

  2. Yii::app()->db ma questo codice è dentro al metodo che estende il componente user. Quindi devi concentrarti solo sul fatto che vuoi quel dato. Sarà il componente user a dartelo. Se un giorno ti va di cambiare la logica di dammiQuelDato(), lo dovrai fare in un solo punto della tua applicazione.

Premesso che non ho ancora ben capito quello che hai fatto (probabilmente mi manca qualche info)

Mi trovo in questa situazione.

Voglio implementare in tutta l’applicazione le funzioni getDevice e setDevice per capire se stanno fruendo dell’aplicazione da ipad, iphone o pc

e quindi penso di rientrare in questa casistica, che hai spiegato.

Ma non mi è chiaro come fare.

Dove hai piazzato la classe che estende CWebUser?

Sto cercando di fare qualcosa tipo Yii::app()->user->cart->azione e vorrei anche creare una classe per gestire il carrello e ancora non saprei se definirla come component o altro.

consigli?

Consigli? "rompi Yii e scopri cosa non ha per sapere cosa devi aggiungere =)".

Io per esempio ad un certo punto posso scrivere Yii::app()->user->getPicchio(); Sicuramente Yii mi lancerà un’eccezione che mi dirà che CWebUser (una classe di Yii) on ha quel metodo. Se io voglio che Yii::app()->user->getPicchio() funzioni, o aggiungo il metodo a CWebUser o creo una mia classe che estende da CWebUser. Nel primo caso sovrascriverei il framework. MALE! Questa soluzione non è molto bella: potrebbe cambiare il codice dello stesso framework e se domani dovessi aggiornarlo la tua classe andrebbe riscritta. Oppure vai nel file di configurazione e decidi tu qualche classe usare.

Questo è quello che trovi nel tuo file di configurazione.




    'components' => array(

        ...

        'user' => array(

            'allowAutoLogin' => true,

        ),



Questo è quello che puoi fare per usare una TUA classe che fa quello che vuoi




    'components' => array(

        ...

        'user' => array(

            'class' => 'LaTuaClassePersonale',

            'allowAutoLogin' => true,

        ),



In questo modo, stai dicendo che Yii::app()->user corrisponde alla classe LaTuaClassePersonale. Se questa classe si limitasse ad estendere CWebUser il funzionamento dell’intero sito sarebbe invariato.




class LaTuaClassePersonale extends CWebUser {}



Se ora aggiungi un metodo, pubblico, alla clase LaTuaClassePersonale, questo sarà raggiungibile da Yii::app()->user.

Spero non sia per visualizzare versioni del sito diverse a seconda dell’user-agent :D

Perchè implementarle? Lo fa già yii.

e come?

che comando devo guardarmi?

Si può partire da qui. Però ricorda sempre che stai usando un framework. L’unica cosa che devi implementare, è la logica della tua applicazioni. Yii, ha già fatto tutto il resto per te.

Io consiglierei un approccio tramite behavior.

Mi spiego meglio. Come fa’ notare moomba questo aproccio e’ corretto solo se il metodo e’ utilizzato ovunque e rimarra’ tale anche in futuro.

In caso contrario conviene sempre creare un metodo che sia possibile agganciare a runtime quando serve ( praticamente un metodo presente in un behavior ) e nel caso in cui serva sempre si puo agganciare di default alla classe CWebUser tramite : …




'components' => array(

        ...

        'user' => array(

            'allowAutoLogin' => true,

            'behaviors'=>array(

                 'possoAttaccare'   => array( 'class' => 'UserBehaviors' ),

            ),  

        ),



In questo modo non si e’ costretti a subclassare CWebUser lasciando l’applicazione e la funzionalita’ molto piu’ portabili.

ciao a tutti, ne approfitto per salutare la comunità italiana di yii

che seguo da un pò di tempo, mi sto avvicinando pian piano a questo interessante framework.

comincio subito con una domanda:

seguendo la guida ufficiale di yii sull’autenticazione (topics.auth, non mi fa inserire i link ;) )

ho realizzato il mio sistema di autenticazione che legge gli utenti da db postgresql.

tutto funziona correttamente, l’autenticazione la faccio con email e password.

una volta entrato nel blocco dell’autenticazione effettiva, come mi suggerisce la guida

mi copio dei campi del record del mio utente con:


$this->setState('nome_full', $record->cognome." ".$record->nome);

fin qui tutto ok.

dovrei tirarli fuori con:


Yii::app()->user->nome_full

allora vi chiederete… che problema hai!? :rolleyes:

in home page ho questo pezzo di codice qui:




array('label'=>'Login', 'url'=>array('/site/login'), 'visible'=>Yii::app()->user->isGuest),

array('label'=>'Logout ('.Yii::app()->user->nome_full.')', 'url'=>array('/site/logout'), 'visible'=>!Yii::app()->user->isGuest),



ovviamente il buon Yii mi dice che nome_full non è definita.

infatti se provo a scrivere questo:




$t = ""; if(isset(Yii::app()->user->nome_full)){$t = Yii::app()->user->nome_full;}

array('label'=>'Logout ('.$t.')', 'url'=>array('/site/logout'), 'visible'=>!Yii::app()->user->isGuest),



l’esecuzione va a buon fine.

voi cosa mi consigliate? perchè a me sembra di snaturare

un pò la logica del framework.

so che non è un grande problema, però in questo modo ne approfitto per presentarmi e ringraziare tutti gli utenti che hanno messo in sezione italiana del buon codice commentato e comprensibile dal quale poter partire.

alla prossima.

Potresti aprire un post nuovo? Molti non leggono i thread con molte risposte =). Detto questo, io ho mostrato come fare quello che chiedi, che cosa non ti piaceva?

PS. Ti prego di creare un altro thread riguardante il tuo specifico problema.