NotORM v Nette

Školení, která pořádám

Nejzásadnější novinkou ve vývoji NotORM je jeho zařazení do Nette Frameworku. Tedy – nejedná se o kompletní převzetí knihovny, ale o zařazení odvozené práce – Nette zatím nepodporuje některé obraty (např. definici vlastní konvence pojmenování sloupců) a využívá odlišnou syntaxi přístupu k tabulkám a sloupcům. Ta je méně magická, takže zatímco v NotORM lze napsat $db->article("url", $url), tak v Nette se musí psát $db->table("article")->where("url", $url). I když je s tím trochu víc psaní, tak je to pro neznalého člověka čitelnější.

Druhým zásadním rozdílem je sjednocení přístupu ke sloupcům a odvozeným tabulkám. Takže zatímco v NotORM znamená $article["author_id"] číslo autora a $article->author odkazuje na jeho záznam, v Nette lze použít oba zápisy ve stejném významu – pokud neexistuje sloupec, tak se hledá navázaná tabulka. Tohle v NotORM dost dobře udělat nejde, protože lze používat konvenci, kdy se vazební sloupec bude jmenovat stejně jako navázaná tabulka.

Komunita okolo Nette je velmi aktivní, což zpětně pomohlo i originálnímu NotORM k opravení několika chyb a přidání nové funkčnosti. Novinky v NotORM (od posledně) jsou tedy tyto:

Páni, to jsem ani netušil, že změn bylo tolik. Všechny změny průběžně dokumentuji (vždy po zveřejnění nové verze).

NotORM také navštívilo jednu slepou uličku – kvůli integraci podpory dibi do hlavního kódu jsem vyčlenil práci s databází do samostatné třídy. Po zahrnutí podpory databází do Nette ale bude asi dibi používané čím dál tím méně, tak jsem ho přestal podporovat i v NotORM.

Jakub Vrána, Seznámení s oblastí, 31.1.2011, diskuse: 51 (nové: 0)

Diskuse

Michal:

Pěkné shrnutí.
V druhém odstavci je v <?php $aricle["author_id"] ?> chybějící 't', tedy nejspíš a mohlo by to být matoucí, ale nechci rýpat :-).

ikona Jakub Vrána OpenID:

Díky za upozornění, opravil jsem to.

Tomáš Fejfar:

<?php $db->transaction = "BEGIN"; ?>
Nechci rýpat, ale tohle je asi tak intuitivní a logické jako
<?php $db->action = "CONNECT" //připojí se k DB?>
Vypadá to, jakože si něco připravím a teď to nějak "odpálím". (v mám příkladu něco jako "doAction()" :) Není logické na to mít metody?
<?php $db->transactionBegin(); ?>
A ještě jeden tip - through skoro nikdo neví jak psát.
<?php
$row
->author()->use('maintainer_id');
$row->author()->via('maintainer_id');
?>
Ale mimo to se NotORM jeví lépe a lépe.

ikona Jakub Vrána OpenID:

Ovládání transakcí se mi taky moc nelíbí. Je to tak proto, že v syntaxi NotORM přistupuje $db->transactionBegin() k tabulce transactionBegin.

through() jsem přejmenoval na via(), je to i výstižnější. Díky za tip, snad to ještě moc lidí nepoužívá.

ikona David Grudl:

Ad spojování tabulek: co přesně znamená to application.author.name?

ikona Vladimír K. Kocourek:

Pokud dobře chápu, $row['application.author.name'] je ekvivalent k $row['application']['author']['name']...

ikona Jakub Vrána OpenID:

Ne, $row['application.author.name'] se napsat nedá.

ikona Jakub Vrána OpenID:

<?php $db->application_tag("application.author.name", "Jakub Vrana") ?> vrátí značky aplikací, jejichž autor je 'Jakub Vrana'. SQL dotaz:

SELECT application_tag.*
FROM application_tag
LEFT JOIN application ON application_tag.application_id = application.id
LEFT JOIN author ON application.author_id = author.id
WHERE (author.name = 'Jakub Vrana')

ikona v6ak:

Třeba by bez podpory dibi nebylo NotORM za
členěno do Nette, takže ta slepá ulička nemusí být zbytečná :-)

Tomáš:

Database v Nette a samotné NotORM si žijú vlastným životom alebo zmeny na jednej strane sú premietnuté aj na stranu druhú (Database -> NotORM, NotORM -> Database)?

Inak povedané, novinky, o ktorých dnes píšeš budú dostupné aj v Nette alebo tam musia byť najprv vymyslené a napísané niekým iným?

Aby som nezabudol - skvelá práca, vďaka za NotORM, Jakube :)

ikona Jakub Vrána OpenID:

David změny v NotORM sleduje a podle svého uvážení je bude dávat i do Nette. Já toho v Nette\Database moc sám dělat asi nebudu. Změn druhým směrem by mělo být minimum.

Tomáš:

Ďakujem :-)

Lopo:

stav podpory dibi (neaktualizovane) v NotORM je dovod, preco som v BailIff-e NotORM zavrhol a pouzil priamo dibi (trosku upravene)
Ak by malo NotORM kompletnu podporu dibi tak by som ho uz pouzival ... aktualne vsak s ohladom na jeho portovanie do Nette fakt neviem co v BailIff-e nakoniec bude, tj ci ostanem pri dibi, alebo zacnem pouzivat Nette\Database, alebo nieco uplne ine ...

Miroslav Hruška:

Chtěl jsem se zeptat (požádat), zda by nebylo možné implementovat NotORM_Result jako "service", to znamená, že by bylo možné tuto třídu nahradit jinou (podobně jako NotORM_Row). Bylo by tak možné přidávat další funkce například pro formátování výsledků dotazů. Všechny aktuální public metody v NotORM_Result by mohli být klidné označeny jako final (aby se v tom nikdo nevrtal). Jde mi například o několikrát diskutované metody fetchAll a fetchAssoc.
<?php
$notORM
->rowClass = 'Moje\Vlastni\Row\Class';
$notORM->resultClass = 'Moje\Vlastni\Result\Class';
?>

Díky.

ikona Jakub Vrána OpenID:

To asi nebude tak jednoduché. NotORM totiž vytváří i objekty třídy NotORM_MultiResult, což je potomek NotORM_Result.

Zkus mi prosím lépe vysvětlit, na co přesně by to bylo potřeba.

Miroslav Hruška:

To je škoda, přiznám se, že samotné jádro jsem až tolik nestudoval. Rád bych přidal nějaké sofistikovanější metody pro formátování výsledku dotazu. NotORM je super ale přeci jen mi tam ještě pár věcí schází:
V NotORM je jediná pomocná metoda pro formátování výsledného pole a tou je fetchPairs, rád bych tam viděl ještě fetchAll (vím, že je to náhrada za iterator_to_array ale občas se to hodí a přiznejme si že psát iterator_to_array není příliš cool) a fetchAssoc (něco jako je v nette, ani to nemusí být tak promakané, stačí pouze néco jako:
<?php
$result
= $db->application->fetcchAssoc('author.name,id=title');
foreach (
$result as $author_name => $apps) {
  foreach ($apps as $id => $title) {
    echo $author_name . ' je autorem ' . $title;
  }
}
?>
nebo
<?php
$result
= $db->application->fetcchAssoc('author.name,id');
foreach (
$result as $author_name => $apps) {
  foreach ($apps as $id => $row) {
    echo $author_name . ' je autorem ' . $row['title'];
  }
}
?>

Na takové ty malé tabulky, ze kterých potřebuji jen rychle néco vytáhnout, je to naprosto super. Ostatně to asi sám znáš z dibi.
Díky za odpověď.

ikona Jakub Vrána OpenID:

Sice to taky není moc cool, ale vždycky si to můžeš napsat zvenku: <?php fetchAssoc($db->application(), 'author.name,id=title') ?>.

Drejk:

var_export+include nie je rychlejsi ako serialize

http://techblog.procurios.nl/k/n618/news/…_export.html

Uvedeny clanok potvrdzuju aj moje skusenosti.

ikona Jakub Vrána OpenID:

Pokud někomu záleží na rychlosti, tak používá opcode cache. V článku je její použití sice zmíněno, ale výsledky chybí. Argument, že když už máme opcode cache, tak můžeme data ukládat rovnou do sdílené paměti, neplatí vždy – např. aktuální verze eAcceleratoru tuto funkci nemá.

talpa:

pouzivam notORM v Nette, co furt nemuzu najit ci nevim jak na to je jak na spojovaci tabulky...
konkretne umim prochazet, ale smazat zaznam ve spojovaci tabulce, to je uz problem... primary key slozene ze 2 sloupcu tam proste neni, respektive je pod jednim nazvem ID , coz je asi spatne. nebo delam neco spatne a v tom pripade bych to mazani rad videl jak na to:) nebyl by priklad?

ikona Jakub Vrána OpenID:

Mazání je popsané na http://www.notorm.com/#persistence, primární klíč se u toho na nic nevyužívá.

Tomáš:

Akým spôsobom sa dajú debugovať/vypisovať SQL queries, ktoré NotORM vykonáva?

Viem, že debug mód je implementovaný cez STDERR ale vôbec neviem, ako s tým pracovať.

Ďakujem.

ikona Jakub Vrána OpenID:

STDERR je definován při spuštění z příkazové řádky a znamená chybový výstup. Při spuštění z webu ho lze definovat na cokoliv, ale to bych raději doporučil použití callbacku.

Vyki:

Zdravím, chtěl jsem se zeptat, kdy se můžeme těšit na další tutorial video k notorm. Našel jsem u těch předešlých videí v seznamu ještě třetí s názvem "Model definition (M from MVC)", ale asi se teprve připravuje. Díky za odpověď,

ikona David Grudl:

No těšit se můžete klidně hned :-)

ikona Jakub Vrána OpenID:

Už jsem jednou slíbil leden, takže nic dalšího pro jistotu slibovat nebudu.

Vyki:

Rád si počkám, ale myslím, že nastala doba, kdy je hodně lidí nalomených k tomu přejít z Doctrine k NOTORM, protože způsob jakým NOTORM funguje a tvoje články, práce a ukázky jsou dost silnými argumenty.

Miroslav Hruška:

Ahoj Jakube, omlouvám se za komentování starého článku ale moc nevím, kde jinde se zeptat. Potřeboval bych při načítání dat zavolat svojí databázovou funkci na počítání cen, klasickým sql bych to zapsal jako:
SELECT name_cz, product_number, CALC_PRICE(price, currency), description_cz. Díky.

ikona Jakub Vrána OpenID:

A otázka zní, jak se to udělá v NotORM?
<?php
foreach ($db->t()->select("name_cz, product_number, CALC_PRICE(price, currency) AS price, description_cz") as $t) {
    $t["price"];
}
?>

Miroslav Hruška:

Jj, NotORM :) Tvé řešení samozřejmě funguje, akorát se tím připravuji o možnost cachovat načítané sloupce, spíše by se mi líbilo něco jako

<?php
foreach ($db->t()->addSelect('CALC_PRICE(price, currency)')->as('price') as $t) {
    $t["price"];
}
?>

navíc tam mám téch sloupců vícero a nechce se mi vracet k (z pohledu NotORM zbytečnému) způsobu zápisu SELECT části SQL dotazu pokaždé, když potřebuji například naformátovat čas nebo spočítat cenu. Dalším mínusem je volání pluginů, které na to mám také napojené (nainstauli plugin, přidám sloupec do tabulky pomocí ALTER) a pak už si jen rozšířím tabulku pomocí
<?php $grid->addColumn('nazev_sloupce', 'titulek'); ?>

Tento přístup pro mě má hned 3 nevýhody, nešlo by to tedy vyřešit nějak elegantněji?
Díky za reakci

ikona Jakub Vrána OpenID:

Už jsem o přidání této metody také uvažoval, mě by se hodila hlavně při spojování tabulek. Takže to asi časem do NotORM opravdu zařadím.

Miroslav Hruška:

Jo, to by bylo super Jakube, včera jsem na něco podobného narazil při agregaci, potřeboval jsem počítat hodnoty objednávek z různých stavů, ale pomocí klasického foreach to nešlo, objednávky jsou totiž malinko složitější a tak jsem musel psát natvrdo SUM(orders.products.price_dph) as price_dph_sum a pak opět vydatlovávat ty sloupce. Je to asi poslední věc, která mi na NotORM chybí (teda zatím, časem se ještě asi něco najde :)

Stano Paška:

Dobrý deň,

dá sa nejako zistiť počet riadkov výsledku a potom na to ešte aplikovať limit?

Problém je pre dibi riešený v článku MVC paradox, dá sa to nejako aj v NotORM?

Ďakujem za odpoveď.

ikona Jakub Vrána OpenID:

Ano, celkem snadno:

<?php
$table
= $db->table()->where($where);
$count = $table->count('*');
$table->limit($limit);
?>

Stano Paška:

Hmm, presne takto som to mal, ale zrejme to v dibi branchi nefunguje.
Count mi vráti správny počet, ale keď aplikujem limit sa už nespraví sql príkaz.
Používam dibi verziu kôli Typo3, aby som nemal dve konekcie na databázu.
Neplánujete aktualizovať dibi branch?

ikona Jakub Vrána OpenID:

Ne, dibi branch již dále nevyvíjím.

Stano Paška:

Aha, po novom vo funkcii limit nulujete $this->rows.
Tak si to tam idem doroobiť.

Pepko:

Po dlouhé době, jsem se odhodlak vyzkoušení této knihovny. Zezačítku jsem dost bojoval s "friend visibility emulation". Nakonec jsem zkusil zakázat eaccelerator a ejhle, ono to pomohlo.

Druhý krok, který mne ale zastavil je "Use of undefined constant STDERR - assumed 'STDERR'". Pouzivam PHP 5.2.6 na Linuxu. Co jsem na internetu koukal, tak tento problem by se mel tykat spise Windows serveru:-/

ikona Jakub Vrána OpenID:

STDERR se používá při nastavení <?php $notORM->debug = true; ?> a hodí se při spuštění z příkazové řádky. Při spuštění z webu lze tuto vlastnost nastavit na vlastní callback. Viz http://www.notorm.com/#api

Pepko:

Omlouvám se, moje chyba. Koukal jsem na jeden postup na Nette fóru, kde to bylo napsáno že by to mělo fungovat i s NCallbackem.

ikona Jakub Vrána OpenID:

Ohledně eAcceleratoru – jaká to byla verze, jaká verze PHP, jaký OS a jak se „bojování“ projevovalo?

Pepko:

Pokud mám zapnutý eAccelerator a do Nette projektu si přidám i NotORM knihovnu, dostávám toto:

Notice: Undefined property: NotORM::$structure
File: /www/publiclibs/NotORM/NotORM/Result.php    Line: 20

Pokud v Nette Debuggeru vypnu strictMode, tak přirozeně skončí běh aplikace chybou:
Fatal Error: Call to a member function getPrimary() on a non-object
File: /www/publiclibs/NotORM/NotORM/Result.php    Line: 20

Vlastně se v tomto případě pak NotORM pokouší pracovat s tabulkou structure v DB.

Po chvíli zkoumání jsem zjistil, že problém dělá zřejmě "friend visibility emulation". Zkusil jsem si tedy vytvořit jednoduchou abstrakní třídu a další dvě třídy, které z ní dědí + krátký kus kódu. Tento kód jsem spustil mimo svůj Nette projekt s tímto výsledkem.
První spuštění proběhlo v pořádku. Při druhém mi vyskočila chyba:
Fatal error: Cannot access protected property DruhaTrida::$test

Pokud vypnu eAc

Můj server:
PHP 5.2.6
eAccelerator 0.9.5.3
OS Linux CentOS

ikona Jakub Vrána OpenID:

Mohl bys to prosím vyzkoušet s aktuální verzí PHP a eAcceleratoru? Pokud chyba přetrvá, tak eAcceleratoru nahlásit chybu?

Schmutzka:

Nešel by udělat nějakýc jednoduchý přehled, jak dělat ty základní věci? Vidím největší potíž s pouhým AND a OR aj.

Také by byla užitečná tabulka, jak na příkaz v sql, v dibi, případně i v dotrine a jak v notorm. Třeba těch základních 10, aby se lépe přecházelo na notorm. Moc by mi to pomohlo.

(Klidně graficky zpracuji zadaná data.)

ikona Jakub Vrána OpenID:

Viz http://www.notorm.com/#examples.

ikona Schmutzka:

Tak si sám odpovím:

Pokud s notorm začínáte, nebo potřebujete vědět, jak co napsat (OR, IN s více poli, JOIN, COUNT("*")), vytvořil jsem přehlednou tabulku příkazů, tedy helpku, jak to psát: http://bit.ly/SQLcQ

Naleznete zde i fetchSingle() a alternativy k jiným dibi-like příkazům. Pro uživatele dibi bude přechod mnohem jednodušší.

Snad vám bude nápomocna a ušetří spousty hodin a nervů :)

Honza:

Ahoj, mohl bys prosím opět zpřístupnit tvoji tabulku příkazů?
Již je nedostupná.

Díky moc!

Honza

Petr Ogurčák:

Měl bych dotaz, jak s příchodem Nette 2 a Dependency Injection používáš NotORM v Nette?
Modely stále statické? Načítáš modely přes ModelLoader?

ikona Jakub Vrána OpenID:

Modely mám stále statické, tedy alespoň jejich většinu. Je to totiž hrozně pohodlné, v šabloně můžu rovnou volat Article::getActives(). Zároveň mě to nijak neomezuje, takže nemám racionální důvod to opouštět.

Experimentuji i s normálními metodami pro práci s jedním konkrétním objektem (např. <?php $article = new Article($row); $article->visit(); ?> ve srovnání se statickým <?php Article::visit($row); ?>), na čemž jisté výhody spatřuji.

Janáček:

Dobrý den, potřeboval bych poradit s problémem propojení více tabulek.

Mám 4 tabulky:

company
- id
- name
- address_id

address
- id
- street_id
- city_id

street
- id
- name

city
- id
- name

Potřebuji vyfiltrovat firmy, které mají v adrese (ulici nebo městě) nějaké jméno např. Dobřichovice

Když zkouším

$db->company('address.street.name like "%Dobřichovice%" or address.city.name like "%Dobřichovice%"')

Tak to samozřejmě nefunguje ...

Děkuji za radu

ikona Jakub Vrána OpenID:

Se správně nastaveným kódováním mi to normálně funguje.

Vložit komentář

Používejte diakritiku. Vstup se chápe jako čistý text, ale URL budou převedeny na odkazy a PHP kód uzavřený do <?php ?> bude zvýrazněn. Pokud máte dotaz, který nesouvisí s článkem, zkuste raději diskusi o PHP, zde se odpovědi pravděpodobně nedočkáte.

Jméno: URL:

avatar © 2005-2017 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení Creative Commons. Můžeme si tykat. Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset. Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.