contributte / planette-site

💀 [DISCONTINUED] All the roads go through the Planette
https://planette.vercel.app
MIT License
9 stars 3 forks source link

2015-04-24: nette-doctrine #40

Open paveljanda opened 7 years ago

paveljanda commented 7 years ago

V tomto tutoriáli sa naučíte sprevádzkovať spoluprácu Nette s ORM Doctrine. Doctrine bude následne vo vašej aplikácii vystupovať ako Model.

Predhovor

Doctrine je pokročilý ORM framework, ktorý posúva možnosti a pohodlie práce s Modelom o veľký kus dopredu. V tomto tutoriáli sa naučíte "dosadiť" Doctrine do pozície Modelu, vyskúšate si prácu s konzolovým rozhraním doctrine-cli a sprevádzkujete napojenie Doctrine na vstavaný profiler.

Aby konzolové rozhranie správne pracovalo aj v prostredí Windows, je potrebné správne nakonfigurovať niekoľko tzv. "environment premenných" prostredia Windows. V tomto tutoriáli nájdete podrobný postup ako PHP na konzoli sprevádzkovať. Užívateľov unixových operačných systémov sa táto poznámka netýka.

Čo budete potrebovať?

Štruktúra projektu

doctrine/
  data/
    fixtures/
    sql/
  migrations/
  schema

tieto zložky slúžia na skladovanie súborov pre konzolový program doctrine-cli. Jedná sa predovšetkým o konfiguračné súboory YAML a generované SQL skripty

Fungovanie konzolového rozhrania nie je nutným požiadavkom prevádzky Doctrine v Nette Framework. Výraznou mierou však spríjemňuje prácu a vývoj aplikácií. Preto vám odporúčame, aby ste si konzolové rozhranie sprevádzkovali.

Tým je projekt pripravený. Výslednú štruktúru znázorňuje následujúci obrázok:

nette-doctrine-structure2.png

Doctrine v rámci Nette Framework

Knižnice Doctrine bude "naťahovať" RobotLoader, preto skontrolujte jeho konfiguráciu v app/config.ini. Okrem toho, do súboru zapíšte konfiguráciu databázovehého pripojenia. V tejto chvíli ju zapíšte do sekcie common, hneď za konfiguráciu RobotLoadera:

; == database ==
database.driver = mysql
database.host = localhost
database.username = php
database.password = php
database.database = nette_doctrine
database.profiler = true

Teraz sa zamerajte na súbor app/bootstrap.php. Do tohto súboru sa zvyčajne ukladá kód, ktorý inicializuje databázové spojenie - databázovému enginu je predaná konfigurácia zapísaná v app/config.ini. Na konci súboru bootstrap je potom aplikácia spustená.

Kedže konzolové rozhranie nepracuje s aplikáciou, musíte sa nejakým spôsobom vyhnúť volaniu

$application->run();

Najjednoduchšie to spravíte tak, že konfigurácia DB enginu sa vykoná v inom súbore a tento v bootstrap.php "nainkludujete". Aby ste však mohli pristupovať ku config.ini tak ako ste zvyknutý ( pomocou Environment::loadConfig() ) je nutné Nette/loader.php natiahnuť už v tomto separátnom súbore. Vytvorte teda nový súbor app/bootstrap.db.php a na jeho začiatok vložte kód

<?php

require LIBS_DIR . '/Nette/loader.php';

Zároveň rovnaký riadok zmažte z app/bootstrap.php a na jeho miesto vložte kód

require(dirname(__FILE__) . '/bootstrap.db.php');

Do nového súboru teraz treba vložiť kód, ktorý predá Doctrine databázovú konfiguráciu. Táto musí byť vo forme pomerne nepekného, tzv. dsn reťazca. Je to obyčajný String, v ktorom je každá časť konfigurácie (DB driver, server, meno, heslo) oddelená nejakým separátorom. Schéma tohto stringu je približne takáto

dbDriver://dbUsername:dbPassword@server/database

Na mieste dbDriver je možné použiť niektorý z podporovaných driverov

Ostatné sekcie dsn reťazca sú samovysvetľujúce. Do app/bootstrap.db.php je teda potrebné vložiť kód, ktorý dsn reťazec zostaví z konfigurácie uloženej v app/config.ini

Environment::loadConfig();

$dbConfig = Environment::getConfig('database');
$conn = Doctrine_Manager::connection($dbConfig->driver . '://' . $dbConfig->username . ':' . $dbConfig->password . '@' . $dbConfig->host . '/' . $dbConfig->database);

if ($dbConfig->profiler) {

}

riadok s kódom Environment::loadConfig() zmažte z app/bootstrap.php!

Nakoniec je nutné niekam uložiť konfiguráciu (umiestnenie) pracovných zložiek pre konzolové rozhranie. doctrine-cli si ich vo vhodný moment z tohto miesta vytiahne a využije pre svoje fungovanie. Ako najvhodnejší kandidát na úschovu týchto údajov sa javí globálne dostupná statická trieda Nette\Environment, ktorá je na takéto účely priamo určená. Pridajte do app/bootstrap.db.php následujúci kód (súbor môžete následne zavrieť)

Environment::setVariable('doctrine_config',
    array(
        'data_fixtures_path' => dirname(__FILE__) . '/doctrine/data/fixtures',
        'models_path'        => dirname(__FILE__) . '/models',
        'migrations_path'    => dirname(__FILE__) . '/doctrine/migrations',
        'sql_path'           => dirname(__FILE__) . '/doctrine/data/sql',
        'yaml_schema_path'   => dirname(__FILE__) . '/doctrine/schema'
    )
);

Súbor app/bootstrap.db.php môžete využiť pri unit testoch ako bootstrapový súbor, ktorý vás pripojí k testovacej databáze.

Konzolové rozhranie doctrine-cli

Do súboru app/config.ini pridajte sekciu console, ktorá bude dediť od sekcie development.

Ak pracujete na unixovom operačnom systéme, vytvorte v zložke nette-doctrine/scripts súbor doctrine-cli a nastavte mu spustiteľný príznak

touch scripts/doctrine-cli
chmod +x scripts/doctrine-cli

Následne do neho vložte kód

#!/usr/bin/env php

<?php

define('APP_DIR', dirname(__FILE__) . '/../app');
define('LIBS_DIR', dirname(__FILE__) . '/../libs');

require dirname(__FILE__).'/../app/bootstrap.db.php';
$cli = new Doctrine_Cli(Environment::getVariable('doctrine_config'));
$cli->run($_SERVER['argv']);

Skúste teraz skript spustiť bez parametrov

nette-doctrine-unix1.jpg

doctrine-cli a Windows

Na dosiahnutie rovnakej funkčnosti pod operačným systémom Windows musíte vyvinúť trocha viac úsilia. Predpokladajme, že máte Windows XP (pod Windows Vista a Windows 7 je postup len veľmi málo odlišný) a PHP máte nainštalované v zložke C:\php. Túto zložku je nutné pridať do environment premennej PATH:

nette-doctrine-win1.png

nette-doctrine-win2.png

assoc .php=phpfile
ftype phpfile="C:\php\php.exe" -f "%1" -- %~2

Gratulujeme, práve ste asociovali súbory s príponou .php s vaším PHP interpretom. To znamená, že všetky súbory .php sú odteraz spustiteľné a predané do C:\php\php.exe na spracovanie.

Ostáva už iba vytvoriť konzolové rozhranie doctrine-cli vo vašom Windows operačnom systéme. Vytvorte súbor nette-doctrine/scripts/doctrine-cli.php. Jeho obsah je veľmi, veľmi podobný ako v prípade unixovej verzie

<?php

define('APP_DIR', dirname(__FILE__) . '/../app');
define('LIBS_DIR', dirname(__FILE__) . '/../libs');

require dirname(__FILE__).'/../app/bootstrap.db.php';
$cli = new Doctrine_Cli(Environment::getVariable('doctrine_config'));
$cli->run($_SERVER['argv']);

Skúste spustiť skript bez parametrov

nette-doctrine-win4.png

doctrine-cli v akcii (vygeneruj mi Model)

Už letmý pohľad na výpis doctrine-cli prezrádza silu tohto skriptu. Doctrine prostredníctvom neho poskytuje silné nástroje automatizácie práce. Štruktúru vašej biznisovej logiky je možné zapísať (reprezentovať) troma rôznymi entitami

Prvé dva sú pre vašu aplikáciu nepostrádateľné a budú jej nedeliteľnou súčasťou. A hlavným kúzlom doctrine-cli je, že dokáže z jednej entity vygenerovať zvyšné dve

triptich.png

doctrine-cli dokáže napr. z existujúcej databázy vygenerovať php kód Modelov. Alebo naopak, z YAML konfiguračného súboru dokáže pripraviť databázovú schému a php Modely (najčastejší model vývoja). Poďme sa na kúzlo tohto Doctrine triptychu pozrieť bližšie.

V zložke app/doctrine/schema vytvorte súbor schema.yml. Súbory YAML (prípona .yml) sú konfiguračné súbory s formátom vysoko čitateľným pre človeka. Na rozdiel od XML súborov sa v nich človek dokáže zorientovať omnoho jednoduchšie a to dokonca keď sa jedná o stromové štruktúry. Súbor app/doctrine/schema/schema.yml definuje schému našej databázy (tabuľky a ich stĺpce). Poďme si takú jednoduchú schému vygenerovať

Employee:
  columns:
    name: string(50)
  relations:
    Phonenumbers:
      type: many
      class: Phonenumber
      local: id
      foreign: employee_id

Phonenumber:
  columns:
    employee_id: integer
    phonenumber: string(50)
  relations:
    Employee:
      local: employee_id
      foreign: id

Ako vidíte, naša aplikácia bude obsahovať dve tabuľky s prepojením 1:N. Všimnite si definíciu tabuľky alebo ich prepojenia. Všetko je zreteľné na prvý pohľad. Skúste ešte definovať obsah týchto tabuliek, aby ste inštaláciu Doctrine mohli otestovať s nejakými demo údajmi

app/doctrine/data/fixtures/data.yml

Employee:
  Employee_1:
    name: John Doe
    Phonenumbers: [john_home, john_work, john_desk]
  Employee_2:
    name: Betty Lee
    Phonenumbers: [betty_home, betty_work]

Phonenumber:
  john_home:
    phonenumber: 555 123 456
  john_work:
    phonenumber: 332 546 789
  john_desk:
    phonenumber: 555 456 879
  betty_home:
    phonenumber: 555 649 879
  betty_work:
    phonenumber: 332 456 546

Opäť veľmi čitateľný zápis. Teraz už iba ostáva konfiguračné súbory predhodiť konzolovému rozhraniu doctrine-cli a nechať ho urobiť svoju prácu

./scripts/doctrine-cli build-all-load

nette-doctrine-build1.png

Hoďte očkom prosím na vašu databázu, alebo do zložky app/models

nette-doctrine-table1.png

nette-doctrine-table2.png

Zapojte vaše vygenerované Modely do práce - nech vám napr. vylistujú všetky telefónne čísla, ktoré patria Johnovi. Dopíšte do app/models/Employee.php túto statickú metódu

public static function getByName($name)
{
    $q = Doctrine_Query::create()
        ->from('Employee e')
        ->leftJoin('e.Phonenumbers p')
        ->where('e.name = ?', $name);

    $result = $q->execute();
    return ($result) ? $result : null;
}

Práve ste použili DQL (Doctrine query language) - veľmi mocný dotazovací jazyk, ktorým vás Doctrine odtieňuje od rôznych enginov databáz. Využite túto metódu v niektorom presenteri a zobrazte si výsledok v šablóne. Editujte app/presenters/HomepagePresenter.php a do metódy renderDefault dopíšte

$this->template->employee = Employee::getByName('John Doe');

Do šablóny tohto View dopíšte (do druhého DIVu)

<pre>{? print_r($employee->toArray())}</pre>

a otvorte domovskú stránku projektu

nette-doctrine-web.png

Gratulujeme, vaša prvá stránka vydolovala údaje z databázy v spolupráci s Doctrine. Možnosti samotnej práce s Modelmi ďaleko presahujú rámec tohto tutoriálu, preto si všetky pokročilé techniky prosím naštudujte v oficiálnej dokumentácii.

Profiler

V úvode sme vám sľúbili aj postup ako Doctrine napojiť na profiler Nette Framework. Všímavejší istotne postrehli, že v súbore app/bootstrap.db.php sme si pre profiler pripravili miesto

$dbConfig = Environment::getConfig('database');
$conn = Doctrine_Manager::connection($dbConfig->driver . '://' . $dbConfig->username . ':' . $dbConfig->password . '@' . $dbConfig->host . '/' . $dbConfig->database);

if ($dbConfig->profiler) {
    // tu príde kód
}

Do prázdneho miesta dopíšte tento kód

    $profiler = new Doctrine_Connection_Profiler();
    $conn->setListener($profiler);
    Debug::enableProfiler();
    Debug::addColophon('fetchDoctrineEvents');

Na poslednom riadku sme do metódy Debug::addColophon() predali callback na funkciu fetchDoctrineEvents. Musíme ju teda doplniť do kódu. Napr. na samotný koniec suboru app/bootstrap.db.php (mimo horeuvedený IF!)

function fetchDoctrineEvents()
{
    $profiler = Doctrine_Manager::getInstance()->getCurrentConnection()->getListener();

    $queries = 0;
    $out = '<br />';
    foreach ($profiler as $event) {
        $evName = $event->getName();

        if ($evName == 'execute') {
            $queries++;
            $out .= '[' . number_format($event->getElapsedSecs() * 1000, 3) . 'ms]<br />'. $event->getQuery() . '<br />';
        }

        $params = $event->getParams();
        if(!empty($params)) {
            $out .= print_r($params, true) . '<br /><br />';
        }
    }

    return array(
        $profiler->count() . ' Doctrine events',
        $queries . ' sql queries',
        $out
    );
}

Spustite hlavnú stránku ešte raz

nette-doctrine-profiler.png

Zhrnutie

Náš tutoriál je na konci. naučili ste sa v ňom naprogramovať podporu ORM frameworku Doctrine do Nette Framework. Sprevádzkovali ste konzolové rozhramie doctrine-cli (užívatelia Windows okrem toho sprevádzkovali vykonávanie skriptov PHP v konzoli), zoznámili ste sa s konfiguráciou DB schémy a demo údajov pomocou súborov YAML. Pomocou doctrine-cli ste z týchto údajov vygenerovali DB schému a PHP Modely. Modely ste následne dokázali využiť v presenteroch Nette. A nakoniec ste prepojili Nette a Doctrine profiler a jeho údaje vykreslili na stránke.

paveljanda commented 7 years ago

author: srigi (srigi@srigi.sk)