Ciaoo ^^

Ciao ragazzi,

come probabilmente immaginerete sono un nuovo utente yii. Vengo da CodeIgniter ma alla fine la mia scelta è ricaduta su Yii. Un framework un pò ostrico all’inizio ma moolto potente a quanto pare e molto modulare. Purtroppo però sono proprio alle prime armi e mi trovo un po’ spiazzato.

Se avete qualche minuto da dedicarmi avrei qualche paio di domande (tutte banali e scontante temo :S ) tra cui:

  1. Nella guida c’è un’ampia sezione dedicata al testing di yii (TDD), con riferimenti a Selenium e PhpUnit… ma sono cose che mi servono per iniziare o posso saltarle e studiarmele alla fine?

  2. Ho cominciato a seguire la guida di yii che è presente su questo sito. Tuttavia vedo che mi fa usare la shell yii, ma non capisco il perchè. Ovvero, non si farebbe prima ad usare Gii (che se non vado errato fa le stesse cose della console yii solo che le fai via browser)? Inoltre, Gii mi permette di fare le stesse cose che farei con la shell yii o è un pò limitato?

  3. Ogni classe/modulo/helper, ecc che uso inizia con una "C"…ad esempio CHttpCookie. Per cosa starebbe quindi questa C? Controller forse?

  4. Cosa mi consigliate di leggere/seguire per iniziare praticamente da zero con yii?

Grazie mille per l’attenzione,

Ciauz!

Ciao Drake

Rispondo alle tue domande, che non sono affatto scontate:

  1. Il test lo puoi saltare a pie’ pari all’inizio

  2. Usa la shell per creare una nuova applicazione, dopo usa Gii. E’ solo che la guida e’ un po’ datata, ma se noti la shell in fondo e’ indicata come deprecated.

  3. Quella C non so per cosa stia, forse per component, serve ad evitare confusione tra le classi del framework e le tue. Quando crei dei component o dei widget, mettigli una lettera all’inizio, io per esempio uso la Z.

Cosi’ se vuoi creare un oggetto, puoi chiamarlo DController ed essere sicuro di non incasinarti con le classi del framework.

  1. Leggi la definitive guide e fai tanta pratica, soprattuto per cose semplici come creare dei crud, personalizzarli, lavorare con i model.

Cerca di rispettare scrupolosamente le best practice, non scrivere mai componenti o widget a meno che sei assolutamente sicuro di seguire la "via di Yii".

Io ho un po’ di esperienza con progetti iniziati con Yii e andati in mra, tutti si incasinano quando vogliono creare componenti fichi sopra Yii e poi fanno solo disastri.

Ricorda la prima regola del buon programmatore: scrivere codice e’ bene, ma copiare e’ meglio. Cerca di ricalcare la struttura delle pagine generate da gii.

Ti capita mai di scrivere del codice e di dire "oh cribbio… ma questo codice una volta funzionava!!!". Ora immagina di scrivere dei test, ovvero del codice che si assicuri del funzionamento di altro codice. Supponi un giorno di avere 500 classi tutte interconnesse tra loro. Se ne modifichi una, funziona tutto come prima? Se hai scritto i tests puoi lanciarli e loro te lo sapranno dire.

Il TDD prevede di scrivere prima il test e poi il codice. Il tuo codice sarà anche perfetto poi. Funzionerà ESATTAMENTE come avevi previsto. Puoi testare eccezioni, errori, tutto. Però va presa con le pinze. Non va testato tutto. Io sto facendo un browser game ed ho scritto i tests solo di 3 classi.

In sostanza parti dal risultato finale di una classe… e piano piano fai in modo che i tests diventino verdi. Il tutto è anche molto piacevole, perchè oltre ad assicurarti al 100% che quello che hai testato non ti riserverà mai soprese, se vuoi ottimizzare il codice sarà il test a dirti che funziona tutto come prima.

Detto questo. Io non ho MAI usato PHPUnit con Yii. Uso i test per codici particolari …

Ci potresti dare un essempio…

Usi del codice tuo… ho qualche soluzione gia esistente tipo PHPUnit?

Nel gioco che sto sviluppando, ho un "tabellone" ad esagoni. Mi sono inventato un sistema per cui utilizzo il piano cartesiano per spostarmi in una delle sei direzioni. Spostarsi diagonalmente fa si che in alcuni casi si debba incrementare il valore della x, in altri casi no. Prima ho disegnato su carta il piano cartesiano con le coordinate, poi ho scritto un test che mi controllasse la classe. Io SO cosa voglio, ma non so che codice devo scrivere. Con il test, ci ho messo pochi minuti a realizzare la classe Coordinata. Senza test, … mi sono imbattuto in diversi problemi che mi avevano tenuto "bloccato" diverse ore …

PS. Non sono un esperto di test, ma sono un amante dello stato d’animo che si raggiunge quando non ci si deve più preoccupare di come va il codice. Basta fare un click e tutti i test testeranno il codice. Credetemi. Avere la certezza MATEMATICA che il vostro codice FA ESATTAMENTE QUELLO CHE VOLETE senza se e senza ma.

Chi fa TDD scrive prima i test e poi il codice. Io scrivo i test solo in momenti particolari: quando sono stanco o quando non ho tempo per scrivere il codice effettivo.


<?php


require_once dirname ( __FILE__ ) . '/../../classes/Coordinata.php';




/**

 * Test class for Coordinata.

 * Generated by PHPUnit on 2011-05-31 at 23:29:23.

 */

class CoordinataTest extends PHPUnit_Framework_TestCase {


    /**

     * @var Coordinata

     */

    protected $object;


    /**

     * Sets up the fixture, for example, opens a network connection.

     * This method is called before a test is executed.

     */

    protected function setUp () {

        $this->object = new Coordinata;


    }


    /**

     * Tears down the fixture, for example, closes a network connection.

     * This method is called after a test is executed.

     */

    protected function tearDown () {

        

    }


    public static function provider () {

        return array (

            array ( 0, 0, array ( 'x' => 0, 'y' => 0 ) ),

            array ( 1, 0, array ( 'x' => 1, 'y' => 0 ) ),

            array ( 0, 1, array ( 'x' => 0, 'y' => 1 ) ),

            array ( -1, 0, array ( 'x' => -1, 'y' => 0 ) )

        );


    }


    /**

     * @dataProvider provider

     */

    public function testGetPosition ( $x, $y, $coordinata ) {

        $obj = new Coordinata ( array ( 'x' => $x, 'y' => $y ) );

        $this->assertEquals ( $obj->getPosition (), $coordinata );


    }


    public function testInitialPositionIsZeroZero () {

        $obj = new Coordinata ( );

        $this->assertEquals ( $obj->getPosition (), array ( 'x' => 0, 'y' => 0 ) );


    }


    public function testSetPosition ( ) {

        // Remove the following lines when you implement this test.

        $this->markTestIncomplete (

                'This test has not been implemented yet.'

        );


    }


    public static function providerMuoviASinistra () {

        return array (

            array ( 0, 0, array ( 'x' => -1, 'y' => 0 ) ),

            array ( 1, 0, array ( 'x' =>0, 'y' => 0 ) ),

            array ( 0, 1, array ( 'x' => -1, 'y' => 1 ) ),

            array ( -1, 0, array ( 'x' => -2, 'y' => 0 ) )

        );


    }


    /**

     * @dataProvider providerMuoviASinistra

     */

    public function testMuoviASinistra ($a, $b, $c) {

        $obj = new Coordinata ( array (

                    'x' => $a,

                    'y' => $b,

                        ) );

        $obj->muoviASinistra();

        $this->assertEquals ( $obj->getPosition (), $c );

    }


    public static function providerMuoviADestra () {

        return array (

            array ( 0, 0, array ( 'x' => 1, 'y' => 0 ) ),

            array ( 1, 0, array ( 'x' => 2, 'y' => 0 ) ),

            array ( 0, 1, array ( 'x' => 1, 'y' => 1 ) ),

            array ( -1, 0, array ( 'x' => 0, 'y' => 0 ) )

        );


    }


    /**

     * @dataProvider providerMuoviADestra

     */

    public function testMuoviADestra ($a, $b, $c) {

        $obj = new Coordinata ( array (

                    'x' => $a,

                    'y' => $b,

                        ) );

        $obj->muoviADestra();

        $this->assertEquals ( $obj->getPosition (), $c );


    }


    public static function providerInAltoASinistra () {

        return array (

            array ( 0, -1, array ( 'x' => -1, 'y' => 0 ) ),

            array ( 1, -1, array ( 'x' => 0, 'y' => 0 ) ),

            array ( 1, 0, array ( 'x' => 1, 'y' => 1 ) ),

            array ( 0, 0, array ( 'x' => 0, 'y' => 1 ) )

        );


    }


    /**

     * @dataProvider providerInAltoASinistra

     */

    public function testMuoviInAltoASinistra ( $a, $b, $c ) {

        $obj = new Coordinata ( array (

                    'x' => $a,

                    'y' => $b,

                        ) );

        $obj->muoviInAltoASinistra ();

        $this->assertEquals ( $obj->getPosition (), $c );


    }


    public static function providerInAltoADestra () {

        return array (

            array ( 0, 0, array ( 'x' => 1, 'y' => 1 ) ),

            array ( 0, -1, array ( 'x' => 0, 'y' => 0 ) ),

            array ( -1, 0, array ( 'x' => 0, 'y' => 1 ) ),

            array ( 1, -1, array ( 'x' => 1, 'y' => 0 ) )

        );


    }


    /**

     * @dataProvider providerInAltoADestra

     */

    public function testMuoviInAltoADestra ( $a, $b, $c ) {

        $obj = new Coordinata ( array (

                    'x' => $a,

                    'y' => $b,

                        ) );

        $obj->muoviInAltoADestra ();

        $this->assertEquals ( $obj->getPosition (), $c );


    }


    public static function providerInBassoASinistra () {

        return array (

            array ( 1, 1, array ( 'x' => 0, 'y' => 0 ) ),

            array ( 0, 0, array ( 'x' => 0, 'y' => -1 ) ),

            array ( 0, 1, array ( 'x' => -1, 'y' => 0 ) ),

            array ( 1, 0, array ( 'x' => 1, 'y' => -1 ) )

        );


    }


    /**

     * @dataProvider providerInBassoASinistra

     */

    public function testMuoviInBassoASinistra ( $a, $b, $c ) {

        $obj = new Coordinata ( array (

                    'x' => $a,

                    'y' => $b,

                        ) );

        $obj->muoviInBassoASinistra ();

        $this->assertEquals ( $obj->getPosition (), $c );


    }


    public static function providerInBassooADestra () {

        return array (

            array ( 0, 0, array ( 'x' => 1, 'y' => -1 ) ),

            array ( 0, 1, array ( 'x' => 0, 'y' => 0 ) ),

            array ( -1, 0, array ( 'x' => 0, 'y' => -1 ) ),

            array ( 1, 1, array ( 'x' => 1, 'y' => 0 ) )

        );


    }


    

    /**

     * @dataProvider providerInBassooADestra

     */

    public function testMuoviInBassoADestra ($a, $b, $c) {

        $obj = new Coordinata ( array (

                    'x' => $a,

                    'y' => $b,

                        ) );

        $obj->muoviInBassoADestra ();

        $this->assertEquals ( $obj->getPosition (), $c );

    }


}


?>




Ecco un altro test che ho fatto per crearmi un mio piccolo Model:

Vi spiego lo scenario per farvi comprendere meglio la mia situazione. Sto sviluppando un browser game. Ho bisogno di una classe che gestisca tutto il Model. Quello che vorrei, è qualche cosa di simile:

In particolare vorrei che con del codice come questo


$utenti = new Utenti;

sia poi possibile fare una query in tutta la tabella


$utenti->findAll();

oppure solo alcuni campi


$utenti->findAll(array('nome','cognome'));

e magari in particolari condizioni


$utenti->findAll(array('nome','cognome'),array('id'=>33));

Come faccio a realizzare una cosa del genere? Boh! Creiamo il test. Il grosso del lavoro lo lascio a Netbeans. Ora vi mostro il test che ho scritto per testare $utenti->orderBy();

Io sto dicendo che voglio che $obj->findOrderBy(array(‘id’=>‘desc’)); mi restituisca una query in un modo particolare.




    public function testOrderBy () {

        $obj = new Model ( 'persone', true );

        $this->assertEquals ( 'select * from persone order by id desc', $obj->findOrderBy ( array (

                    'id' => 'desc'

                ) ) );

        $this->assertEquals ( 'select * from persone where pasta = "spaghetti" order by id desc', $obj->findOrderBy ( array (

                    'id' => 'desc'

                        ), array (

                    'pasta' => 'spaghetti'

                ) ) );


    }

Ho scritto il test, ma non ancora il codice di Model. Lanciando il test, questo mi dirà che ho cazzato. Vado a scrivere il codice e se ho fatto tutto bene il test diventerà verde. Io sarò una persona felice. =). Uso i test quando sono in difficoltà. Nel test mettiamo prima il valore che ci aspettiamo, e poi quello che ci ritorna il nostro codice. Il bello del test è che ti dice "occhio che non stai ottenendo il risultato che ti aspetti.

Ecco un altro test banale




    public function testFind () {

        $obj = new Model ( 'capelli', true );

        $this->assertEquals ( 'select * from capelli', $obj->find () );

        $obj = new Model ( 'users', true );

        $this->assertEquals ( 'select * from users', $obj->find () );


    }

Ed ora la parte più bella. Supponiamo che io abbia scritto questo test. Supponiamo che il mio codice faccia schifo, pur funzionando perfettamente. Io posso BUTTARE VIA il mio codice, poi riscriverlo usando i test. Credetemi: è un OTTIMO modo per migliorare il proprio modo di scrivere. Non solo. Potete "passare" un vostro test ad un collega, ed a voi non importa che codice scriverà: se il test passa voi avete la certezza assoluta che il codice del collega si comporta ESATTAMENTE COME VOLETE:


<?php


require_once dirname ( __FILE__ ) . '/../../classes/Model.php';


class ModelTest extends PHPUnit_Framework_TestCase {


    protected $object;


    protected function setUp () {

        $this->object = new Model;


    }


    protected function tearDown () {

        

    }


    public function testCount () {

        $obj = new Model ( 'capelli', true );

        $this->assertEquals ( 'select count(*) num from capelli', $obj->count () );


    }


    public function testFind () {

        $obj = new Model ( 'capelli', true );

        $this->assertEquals ( 'select * from capelli', $obj->find () );

        $obj = new Model ( 'users', true );

        $this->assertEquals ( 'select * from users', $obj->find () );


    }


    public function testOrderBy () {

        $obj = new Model ( 'persone', true );

        $this->assertEquals ( 'select * from persone order by id desc', $obj->findOrderBy ( array (

                    'id' => 'desc'

                ) ) );

        $this->assertEquals ( 'select * from persone where pasta = "spaghetti" order by id desc', $obj->findOrderBy ( array (

                    'id' => 'desc'

                        ), array (

                    'pasta' => 'spaghetti'

                ) ) );


    }


    public function testCountwhere () {

        $this->markTestIncomplete (

                'This test has not been implemented yet.'

        );


    }


    public function testFindAll () {

        $this->markTestIncomplete (

                'This test has not been implemented yet.'

        );


    }


    public function testUpdate () {

        $this->markTestIncomplete (

                'This test has not been implemented yet.'

        );


    }


    public function testCreate () {

        $this->markTestIncomplete (

                'This test has not been implemented yet.'

        );


    }


    public function testDelete () {

        $this->markTestIncomplete (

                'This test has not been implemented yet.'

        );


    }


    public function testTruncate () {

        $this->markTestIncomplete (

                'This test has not been implemented yet.'

        );


    }

    

    public function testLastInsertId () {

        $this->markTestIncomplete (

                'This test has not been implemented yet.'

        );


    }


}

Ho capito, grazie ancora per tutte le risposte cosi esaustive ^^

Però scusate un’altra questione: mi sono accorto di avere molte carenze sulla nuova struttura del php…ad esempio non riesco a capire bene cosa comporti l’uso del $this-> piuttosto che quei famosi 4 punti (::) che vedo spesso nelle funzioni. Insomma sono rimasto indietro al vecchio modo di programmare in php, che non era troppo istanziato ed a oggetti. Cosa mi consigliate quindi per mettermi alla pari e colmare queste lacune? Ah e già che ci siamo, voi quale IDE/editor usate per sviluppare i vostri progetti con yii? (io uso netbeans).

Grazie ancora di tutto,

Byez ^^

Drakes, io ho studiato su questo manuale PHP Objects, Patterns and Practice e mi sono trovato bene. Magari è un po’ avanzato, nel senso che puoi trovare risposta ai tuoi dubbi googleando su internet, però puoi dare un’occhiata alla Table of contents per vedere se ti interessa. Lo stesso libro dovresti trovarlo su amazon.it

Per quanto riguarda l’editor/IDE sono passato da Netbeans a Geany (Linux). Netbeans è fighissimo ma è pesantissimo, mentre a me serviva solo un po’ di colore nel codice (syntax highlighting) e l’auto-indentamento. In ambiente windows ho sentito parlar bene di Notepad++ ma non l’ho mai usato.

$this e’ l’oggetto corrente, la questione e’: chi e’ $this nelle varie pagine?

Dai una occhiata a questa guida per iniziare a orientarti.

@sensorario il tuo post sul TDD e molto informativo… se hai tempo potresti farne un bel wiki articolo…

Grazie ancora per le risposte :D

Ho visto per qualche guida per iniziare col php5…ed ho trovato queste 2:

  1. www.realizzazione-sito.info/guide/php_5

  2. http://php.html.it/guide/leggi/167/guida-programmazione-ad-oggetti-con-php-5/

Cosa dite? Ho provato a guardare anche per dei libri come: php 5: guida completa o php 5: elementi di programmazione, ma mi sembrano troppo esaustivi e completi.

Però non saprei, voi cosa dite?

P.S: Il primo link non sembra affatto male.

io ti consiglio le guide di html.it che sono sempre ottime, ma soprattutto se inizi con una seguila fino alla fine!!!

vedo che spesso le persone saltano di tutorial in tutorial cercando sempre quello più sintetico, ed alla fine non ne hanno seguito uno intero ed ovviamente non c’hanno capito una mazza!