Monday, November 22, 2010

Adatbázis migrációk a Yii-vel

A Rails keretrendszernek köszönhetően az elmúlt pár évben nagy teret hódított az Adatbázis Migrációk (Migrations) használata, még PHP-s környezetben is. Személyesen hallottam olyanról, hogy míg az egész rendszer PHP alatt futott, a programozók a Rails-t használták táblák és kapcsolatok készítésére.

Persze több kevesebb sikerrel megjelentek PHP-vel hajtott alkalmazások is, az egyik ilyen pl. a Doctrine Project. Ebben a cikkben azonban a Pieter Claerhout által publikált, és a Yii alá készített Yii-DbMigrations-t fogjuk ismertetni.

Mire jó ez egyáltalán?

Felmerülhet a kérdés, hogy miért is van szükség ilyen rendszerek használatára. A felvetés jogos, hiszen sima SQL-t használva is készíthetünk táblákat és kapcsolatokat. Valóban, viszont az így készített ún. tábla leírások (schema) kifejezetten az adott adatbásban működnek.

Képzeljük el például, hogy a fejlesztés kezdetén SQLite-ot használtunk és késöbb szeretnénk az adatbézisunkat MySQL alá tenni (mondjuk a LIVE szerveren). Sajnos ilyen esetben az összes tábla leírást újra kell készítenünk, mivel a két adatbázis motorban használt SQL nem kompatibilis. Itt jön a képbe az Adatbázis Migráció.

A lényeg az, hogy adtabázisleíró nyelvtől függetlenül tudunk táblákat és kapcsolatokat készíteni a PHP segítségével. Az így elkészített tábla osztályokat pedig nagyon egyszerűen a kívánt (és támogatott!) adatbázis alá be lehet illeszteni. Külön hab a tortán, hogy arra sem kell emlékeznünk, hogy melyik volt az utolsó lefuttatott tábla osztály, mindezt a Yii-DbMigartions elvégzi helyettünk. Úgy is gondolhatunk rá, mint egy adatbázisra szabott Forráskezelő program (pl: SVN vagy GIT)

Hátrányok

A modul még csak alpha állapotban van.
Jelenleg csak SQLite és MySQL támogatott.
    Installálás és Beállítás

    Miután kicsomagoltuk a zip file-t a szokásos helyre - protected/extensions, győződjünk meg arról, hogy az adatbázissal kapcsolatos beállítások megfelelőek a protected/config/main.php-ben.

    MySQL:
    Data hosted with ♥ by Pastebin.com - Download Raw - See Original
    1. 'components' => array(
    2.     'db'=>array(
    3.         'class' => 'CDbConnection',
    4.         'connectionString'=>'mysql:host=localhost;dbname=my_db',
    5.         'charset' => 'UTF8',
    6.         'username'=>'root',
    7.         'password'=>'root',
    8.     ),
    9. ),


    SQLite:
    Data hosted with ♥ by Pastebin.com - Download Raw - See Original
    1. 'components' => array(
    2.     'db'=>array(
    3.         'connectionString'=>'sqlite:'.dirname(__FILE__).'/../data/my_db.db',
    4.     ),
    5. ),


    A Parancssor beállítása

    Alap esetben természetesen a yiic nem tud a migrate utasításról, hiszen még csak most telepítettük a modult. Ezért be kell állítanunk egy új commandMap-et  a protected/config/console.php file-ban:

    Data hosted with ♥ by Pastebin.com - Download Raw - See Original
    1. 'commandMap' => array(
    2.     'migrate' => array(
    3.         'class'=>'application.extensions.yii-dbmigrations.CDbMigrationCommand',
    4.     ),
    5. ),



    Beállítások tesztelése

    Ha minden jól sikerült, egyszerűen futtassuk le a yiic parancsot a parancssorból:

    Data hosted with ♥ by Pastebin.com - Download Raw - See Original
    1. Yii command runner (based on Yii v1.0.10)
    2. Usage: protected/yiic <command-name> [parameters...]
    3.  
    4. The following commands are available:
    5.  - migrate
    6.  - message
    7.  - shell
    8.  - webapp
    9.  
    10. To see individual command help, use the following:
    11.    protected/yiic help <command-name>

    Reméljük így a migrate parancs már elérhető.

    Migrációk készítése

    Nevvekkel kapcsolatos korlátozások

    A migrációs file-okat a protected/migrations vagy a migrations mappába (a modul könyvtárába) helyezhetjük el. Az file-ok neveit pedig a következő képpen ajánlatos elnevezni:

    m20090614213453_MigracioNeve.php

    A névnek mindig egy 'm' betűvel kell kezdődnie, utána egy 14 karakter hosszú dátumot meghatározó string, egy aláhúzásjel '_' és végül pedig egy szabadon választható MigrációNév.

    Persze, szerencsénkre, ezt automatikusan is megtehetjük a protected/yiic migrate create <MigracioNev> lefuttatásával:

    Data hosted with ♥ by Pastebin.com - Download Raw - See Original
    1. $ protected/yiic migrate create TestMigration
    2. Migrations directory: protected/migrations/
    3.  
    4. Created migration: m20091114210716_TestMigration.php


    Táblaleírások készítése

    Magában a tábla leíró file-ban létre kell hoznunk egy osztályt, aminek a szülő osztálya a CDbMigration, és két kötelező metódusunk az up és down lesz. Reméljük a következő példa kicsit segíteni fog:

    Data hosted with ♥ by Pastebin.com - Download Raw - See Original
    1. class m20090611153243_CreateTables extends CDbMigration {
    2.  
    3.     // Apply the migration
    4.     public function up() {
    5.  
    6.         // Create the posts table
    7.         $t = $this->newTable('posts');
    8.         $t->primary_key('id');
    9.         $t->string('title');
    10.         $t->text('body');
    11.         $t->index('posts_title', 'title');
    12.         $this->addTable($t);
    13.  
    14.     }
    15.  
    16.     // Remove the migration
    17.     public function down() {
    18.  
    19.         // Remove the table
    20.         $this->removeTable('posts');
    21.  
    22.     }
    23.  
    24. }


    Tehát az up() segítségével elkészítjük az új táblát, a down()-nal pedig töröljük.

    Támogatott funkciók

    A migráció osztályban a következő funkciók érhetők el:


    • execute: sima SQL futtatása, ami nem ad vissza értéket.
    • query: sima SQL futtatása, ami értékkel tér vissza.
    • createTable: új tábla készítése
    • newTable: új tábla leírás készítése
    • addTable: táblaleírás hozzáadása a migrációhoz
    • renameTable: tábla átnevezése
    • removeTable: tábla törlése
    • addColumn: oszlop hozzáadása a táblához
    • renameColumn: oszlop átnevezése
    • changeColumn: oszlop változtatása
    • removeColumn: oszlop törlése
    • addIndex: index hozzáadása táblához vagy adatbázishoz
    • removeIndex: index törlése táblából vagy adatbázisból.

    Mezőleíró beállításoknál pedig a következő változók használhatók:


    • primary_key
    • string
    • text
    • integer
    • float
    • decimal
    • datetime
    • timestamp
    • time
    • date
    • binary
    • boolean
    • bool

    Persze ezen kívül lehet adatbázis specifikus mezőket is készíteni, viszont úgy nem tudjuk a programot más adatbázis alá (könnyedén) átemelni.

    Táblák készítése másként

    Data hosted with ♥ by Pastebin.com - Download Raw - See Original
    1. // elso lepes, uj tabla leiras keszitese
    2. $t = $this->newTable('<tableName>');
    3.  
    4. // oszlopok es indexek keszitese
    5. // megj: a funkcio neveibol lehet kovetkeztetni a
    6. // a tabla tipusara
    7. $t->primary_key('id');
    8. $t->string('title');
    9. $t->text('body');
    10.  
    11. // unique - egyedi
    12. $t->index('title');
    13. $t->unique('title');
    14.  
    15. // tabla letrehozasa
    16. $this->addTable($t);


    Migrációk futtatása

    Csak azért mert elkészítettük a tábla-leírásokat, az nem azt jelenti, hogy a táblák már készen is vannak az adatbázisban. A migrate parancs lefuttatásával történik meg mindez:

    Data hosted with ♥ by Pastebin.com - Download Raw - See Original
    1. protected/yiic migrate
    2.  
    3. Migrations directory: protected/migrations/
    4.  
    5. Creating initial schema_version table
    6. === Applying: m20090611153243_CreateTables =====================================
    7.     >> Creating table: posts
    8.     >> Adding index posts_title to table: posts
    9. === Marked as applied: m20090611153243_CreateTables ============================
    10.  
    11. === Applying: m20090612162832_CreateTags =======================================
    12.     >> Creating table: tags
    13.     >> Creating table: post_tags
    14.     >> Adding index post_tags_post_tag to table: post_tags
    15. === Marked as applied: m20090612162832_CreateTags ==============================
    16.  
    17. === Applying: m20090612163144_RenameTagsTable ==================================
    18.     >> Renaming table: post_tags to: post_tags_link_table
    19. === Marked as applied: m20090612163144_RenameTagsTable =========================


    Még itt a végén annyit érdemes megjegyezni, hogy ha most lefuttatnánk a migrate parancsot mégegyszer, semmi nem történne, hiszen a modul megjegyzi, hogy melyik volt az utolsóként lefutott migráció.

    És ennyi! Mindenképpen javaslom az eredeti cikk elolvasását is, mert ott még van egy-két utasítás amire nem tértünk itt ki, de remélem ezek után mindenkinek megjön a kedve egy kis adatbányászáshoz :)



    8 comments:

    1. Jonak tunik a cikk, mindossze pont a migracio masik lenyegere nem kapunk gyakorlati utmutatast.

      ReplyDelete
    2. koszi Carstep,

      nagyon gyakran a module-ok leirasai eleg szukszavuak, viszont nem akarok hozzatenni sem az eredeti szoveghez.

      Egyelore probalom kitalalni, hogy a tobbseg mire kivancsi, ezert "vaktaban" forditgatok cikkeket.

      Nem biztos, hogy ez a legjobb megkozelites de majd meglatjuk

      koszi megegyszer,
      --i

      ReplyDelete
    3. nm, egyebkent mar dolgoztunk egyutt a CakePHP forditasanal, most is be tudok vallalni egy kisebb reszt, bar a Yii-vel meg semennyire sem foglalkoztam ( igaz anno a CakePHP-vel is gyerekcipoben jartam :) )

      Udv
      Sanyi

      ReplyDelete
    4. Sajnos a fonokeimet egyszer sem tudtam meggyozni, hogy a Cake-et hasznaljuk, igy nekem kellett alkalmazkodnom (eloszor a ZendFramework-ot kesobb pedig a Yii-t tanultam igy meg) viszont lemaradtam a Cake fejlodeserol :/

      Egyebkent most Larry Ullman Yii-vel kapcsolatos cikkjeit nezegetem (van neki rendesen), mivel o egy nagyon tapasztalt tech konyviro. Ha van idod es kedved nezz ra, hogy szerinted jo otlet lenne e ezeket a cikkeket magyarra forditani: http://www.larryullman.com/tag/yii/

      --iM

      ReplyDelete
    5. "Persze több kevesebb sikerrel megjelentek PHP-vel hajtott alkalmazások is, az egyik ilyen pl. a Doctrine Project."

      Doctrine ORM köszöni szépen jól megvan, és mivel a symfony-ban ez az alapértelmezett model, igen sokan használják, nagy SIKERrel :D

      amit itt nem látok, viszont érdekelne, hogy tud-e automatikus diffet készínteni a migrációs osztályok legenerálására.

      symfony/doctrine-ban ez úgy működik, hogy a séma leíró fájl és a generált modellek közötti különbségből automatikusan létrejönnek a módosítások.

      1. lépés: módosítod a séma fájlt
      2. lépés: symfony doctrine:generate-migrations-diff
      3. lépés: symfony doctrine:migrate
      4. lépés symfony doctrine:build --all-classes

      szeretek ismerkedni új framework-ökkel, szerintem a Yii forrása nagyon szépen karban van tartva!!

      ReplyDelete
    6. @Firith
      A Doctrine ORM-mel semmi gond nincs, magam is hasznalom, mindossze egy nagy forgalmu szajtnal mar tulsagosan sok fajl beolvasast (I/O) eredmenyez, ezert nagyon is belassulhat tole a rendszer. Mindez persze a Zend Framework-re is ervenyes, amivel nagyon sokszor hasznaljak egyutt - mint magam is. Sajnos a Doctrine ORM sem kepes teljes migraciora, mivel az adatmigraciora nem ad megoldast.

      udv
      Sanyi

      ReplyDelete
    7. @firith,

      sajnos ebben a modulban ilyen nincsen (jelenleg).

      egyebkent en mar irtam vagy ketszer a Yii csapatanak, hogy tamogathatnak a Doctrine-t, de eddig meg nem tortent meg :/

      ja, a "tobb-kevesebb siker"-t azt meg ugy ertettem, hogy amig a Rails-nel mondjuk a programozok 90%-a (vagy tobb) hasznalja a migraciokat, addig a PHPs programozoknal szerintem ez meg se kozeliti a 40-50%-ot. tehat a "sikertelenseget" en az emberekre es a hasznaltsagra ertettem, nem magara a progira.

      --iM

      ReplyDelete
    8. @carstep ha nagy a forgalom akkor jön jól a cache :) doctrine-ban van query és result cache is :) na mondjuk ha a kimenetet is cache-eled akkor még ehhez sem kell eljutni

      bárcsak lenne egy szabad délutánom, estém, úgy megnézném már ez a Yii-t :(

      ReplyDelete