1. díl - Úvod do Doctrine 2 v Nette frameworku

PHP Nette Framework Doctrine Úvod do Doctrine 2 v Nette frameworku

Vítám vás v prvním díle série článků o technologii ORM (objektově relační mapování) v Nette frameworku. Tato technologie je konkurenční klasickému získávání tabulek z databáze pomocí čistého SQL nebo nějaké jeho nástavby jako např. Dibi a umožňuje pracovat s relační databází objektově. Série vám technologii, která se v komerčních aplikacích často využívá, představí na systému pro správu obsahu, kde použijeme asi nejznámější ORM knihovnu pro PHP - Doctrine 2. Osobně nemám rád dlouhé slohy, ale pár slov na úvod je potřeba říci.

Články budou mít za úkol seznámit vás s použitými technologiemi a ukázat, jakým dalším způsobem lze napsat webovou aplikaci. Nebudou proto vysvětleny veškeré detaily týkající se použitých technologií, ale ukáží vám postup při vývoji.

Je proto potřeba mít alespoň základní znalost:

  • frameworku Nette
  • šablonovacího systému Latte
  • OOP v PHP (výjimky, jmenné prostory, rozhraní atd.)
  • znalost Doctrine 2 či jiného ORM je výhodou (ale pochopíte ji během seriálu, doporučuji i průběžně sledovat dokumentaci)

V článcích budou uvedeny mimo jiné i vlastní názory, případné klady nebo zápory použitého algoritmu a tak podobně. Doufám, že pro vás budou přínosné a otevřou vám nové možnosti. :-)

Systém bude umět:

  • registraci a přihlášení uživatele
  • správu kategorií (vytváření, úprava, mazání, schvalování)
  • správu článků (vytváření, úprava, mazání)
  • správu uživatelů (vytváření, úprava)
  • role uživatel/admin
  • překlad do cizích jazyků
  • nastavení účtu (v podstatě jen popis uživatele)

Pro lepší představu si ještě ukažme alespoň 2 screenshoty z hotového systému:

Detail článku Nette a Doctrine CMS

 

Administrace uživatelů v Nette a Doctrine CMS

Představení technologií

Při tvorbě systému budou použity tyto technologie:

Framework Nette

Nette je český framework využívající architekturu MVP (Model-View-Presenter). Obsahuje ale pouze vrstvy VP, pro modelovou má jen databázový wrapper. Je proto čistě na vývojáři, jak si modelovou vrstvu sestaví. Díky tomu máme velmi dobrý základ pro naši aplikaci - nemusíme se téměř starat o bezpečnost aplikace, cachování a vůbec většinu nudných, avšak důležitých věcí za nás framework udělá sám, a my se tak můžeme plně soustředit na samotné úkoly.

S pomocí frameworku tedy můžeme ušetřit mnoho času a to v reálné aplikaci znamená vydělat více peněz. Jiné frameworky jsem (v době, kdy jsem psal článek) nezkoušel, ale jsem přesvědčen, že je Nette velmi kvalitním frameworkem s dobrou komunitou. Jen je škoda, že byla dokumentace velmi dlouho pouze v češtině, a tak se příliš nedostal do světa.

Doctrine 2

Doctrine je tzv. ORM, neboli objektově relační mapování (object-relational mapping), jehož cílem je mapovat objekty na relační databázi. Doctrine nicméně umí oba směry (z entit udělat strukturu databáze a naopak ze struktury databáze vytvořit kostru entit).

S tímto nástrojem můžeme v podstatě zapomenout, že máme nějakou databázi. Veškerá naše práce s daty se týká objektů, SQL příkazy vůbec nejsou potřeba - ORM se o to postará samo.

DQL

Doctrine má i vlastní dotazovací jazyk nazvaný Doctrine Query Language. Syntaxí se velmi podobá SQL, ale rozdíl je v tom, že místo s tabulkami a sloupci pracujeme s objekty a jejich atributy.

Příklad použití DQL:

// takto by vypadal SQL dotaz do databáze
SELECT `name`, `email`, `ip`
FROM `user`
WHERE `id` > 10
ORDER BY `name` DESC

// a takto příkaz vypadá v DQL
SELECT u
FROM Jmenny\Prostor\User u
WHERE u.id > 10
ORDER BY u.name DESC

Velmi podobné, že? DQL obsahuje i pokročilejší konstrukce, jako je řazení, seskupování atd. Je potřeba vytvořit si alias pro vybrané entity (v naše případě písmeno 'u'). Defaultně se entita načítá celá, když ale chceme jen některá data, využijeme k tomu klíčové slovo partial.

Entita

Entita je objekt nesoucí data. Nemá přístup k databázi ani k jiným datovým úložištím. Jejím úkolem je uchovávat a předávat data. Jelikož by ale neměla být pouhou přepravkou, může (a měla by) obsahovat i validaci vstupu, jako je například ošetření délky předávané hodnoty atributu. Také může obsahovat libovolné metody pracující s daty, které jí náleží. Veškeré informace o entitě samotné a jejich atributech zapisujeme pomocí anotací.

Entity manager

Jak z názvu vyplývá, jedná se v podstatě o správce entit. Jeho úkolem je ukládat nové entity (tzv. persistence), odpojovat je z fronty a nebo je úplně smazat. Všechny entity, jejichž data se mají nějakým způsobem projevit v databázi (ať je to SELECT, INSERT, UPDATE nebo DELETE), musí být pod správou Entity manageru.

I když by se mohlo zdát, že se stará o práci s databází, v jeho hlubinách se skrývá objekt využívající vzoru Unit of work (stejně tak se i jmenuje), který tuto úlohu zastává. Obsahuje frontu všech změn a po příkazu všechny změny provede i v databázi.

Jelikož se jedná o automatizaci, máme zde i jednu nehezkou nevýhodu - všechny změny v databázi jsou provedeny podle určitého pořadí (např. prvně je INSERT, poté UPDATE apod.), což může někdy vyvolat nechtěné chování (např. že se vymaže právě vytvořený záznam, protože odpovídá podmínce v DELETE). Všechny nové entity je potřeba dostat pod správu Entity manageru příkazem persist(). Pokud chceme všechny změny provést i v databázi, musíme použít příkaz flush().

Jednoduchá ukázka práce entity s Entity managerem:

// každou entitu je potřeba označit anotací Entity
/**
 * @ORM\Entity
 */
class User
{
        // všechny atributy je potřeba označit anotací @Column, do závorky poté udáváme údaje, jako je datový typ, délku, možnost nullable atd.
        /**
         * @ORM\Column(type="integer")
         * @ORM\Id
         * @ORM\GeneratedValue
         */
        private $id;

        /**
         * @ORM\Column(type="string")
         */
        private $name;


        // obyčejný setter, ve kterém můžeme využít i jednoduchou validaci
        public function setName($name)
        {
                if (strlen($name) > 15) {
                        throw new Exception("Name is too long");
                }

                $this->name = $name;
        }

        public function getName()
        {
                return $this->name;
        }

        // jelikož entita nemá být pouhou obálkou na data, může vykonávat i jednoduché operace
        public function getFullId()
        {
                return "{$this->name}#{$this->id}";
        }

}

// předpokládejme, že máme Entity manager nakonfigurovaný
$user = new User();
$user->setName("Martin");

$entityManager->persist($user);  // uložíme objekt do fronty, zatím se s databází nic nestane
$entityManager->flush();  // provede všechny změny - v našem případě vytvoří nový záznam v tabulce user (odvozen z názvu entity), nový záznam bude mít ID 1

$userFromDb = $entityManager->find("User", 1);  // User je název entity, 1 je ID
echo $userFromDb->getFullId();  // Martin#1

Všimněte si, že entita neumí komunikovat s databází. Doctrine 2 se odprostila od vzoru ActiveRecord a využívá nyní vzor DataMapper.

Doctrine je rozsáhlý nástroj, zde jsem nastínil jen velmi stručně hlavní pojmy. Mnohem více se dozvíte v samotné dokumentaci.

Rozšíření Kdyby

Kdyby je rozšíření Nette frameworku, které obsahuje spoustu užitečných nástrojů. V našem seriálu použijeme Kdyby\Translation na překlad textů a Kdyby\Doctrine na usnadnění práce s Doctrine.

Architektura aplikace

Vrstvy View a Presenter má Nette zabudované v sobě, do těch raději zasahovat nebudeme. Důležité ale je navrhnout si modelovou vrstvu. Naše bude vypadat takto:

  • Entity - objekty přepravující data
  • Fasády - tzv. služby (services), které provádějí určité úkony (ukládání záznamů, editace, získávání atd.), v aplikaci je vždy jen jedna instance dané fasády a mají koncovku Facade
  • Pomocné třídy pro skládání dotazů - uvidíte během seriálu, lze s nimi efektivně skládat DQL dotazy, mají koncovku Query
  • Form factories - třídy pro vytváření a zpracovávání formulářů, mají koncovku FormFactory

Presentery budou pracovat s fasádami a ty budou pracovat s Entity managerem. Proto nikdy v presenteru neuvidíte objekt třídy EntityManager, ale pouze příslušné fasády. Všechny závislosti (ať v presenterech, fasádách nebo form factories) bude automaticky obstarávat DI container Nette.

Všechny presentery budou ve jmenném prostoru App\Presenters, modelové třídy App\Model a formuláře App\Forms.

Abychom neměli v presenterech úplný nepořádek, budeme psát atributy a metody tímto způsobem:

  • prvně atributy
  • action a render metody pro danou stránku pod sebe (actionStranka, renderStranka, actionStranka2, renderStranka2 atd.)
  • zpracování signálů (handle<Signal>)
  • vytváření komponent (createComponent<Component>)

Adresářová struktura

Struktura zůstává stejná dle Nette, jen do složky app/ přidáme složku lang/, do které budeme přidávat jednotlivé soubory sloužící pro překlad.

Kořenový adresář

Kořenový adresář

Složka app/

Složka app/

Složka presenters/

Složka presenters/

To bude z prvního článku vše - chápu, že obsahoval mnoho teorie, ale bez pár úvodních slov to bohužel nejde. V příštím díle vytvoříme základní strukturu naší aplikace.


 

  Aktivity (2)

Článek pro vás napsal Martin Konečný (pavelco1998)
Avatar
Autor se o IT moc nezajímá, raději by se věnoval speciálním jednotkám jako jsou SEALs nebo SAS. Když už to ale musí být něco z IT, tak tvorba web. aplikací v PHP.

Jak se ti líbí článek?
Celkem (6 hlasů) :
4.833334.833334.833334.833334.83333


 


Miniatura
Všechny články v sekci
CMS v Nette a Doctrine 2

 

 

Komentáře

Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zatím nikdo nevložil komentář - buď první!