Přejít k navigační liště

Zdroják » PHP » Nette Framework: Refactoring

Nette Framework: Refactoring

Články PHP, Různé

Minule jsme si ukázali vývoj jednoduché webové aplikace podle architektury Model-View-Presenter v Nette Frameworku. Dnes se ji pokusíme vylepšit, poukázat na kritická místa a předvést jejich správné řešení.

Automat na kávu v minulém díle demonstroval, jak lze webovou aplikaci rozdělit do tří logických vrstev, tedy model, presenter a pohled (view). Zůstaňme u tohoto dělení i nadále a podívejme se, jak můžeme jednotlivé vrstvy vylepšit.

Model

Tuto rovinu aplikace v seriálu záměrně ošidím. Nette Framework je zaměřený především na podporu prezentační vrstvy, přičemž pro model nabízí „jen“ vyšší standard programování v PHP reprezentovaný třídami Object a Debug, dále autoloading nebo třídu Environment, které na vás čekají v šestém díle seriálu. Žádné jiné konkrétní knihovny, třeba pro práci s databází, v něm nenajdeme.

Jde o poměrně důležitý rys frameworku, který lze přeložit jako: „používejte knihovnu která vám vyhovuje, žádný styl práce vám nenutíme.“ Důsledná nezávislost na databázové vrstvě vám dovolí používat ORM nástroje jako je Doctrine či Propel, knihovnu Zend_Db_Table nebo z opačného ranku například Dibi. Poslední jmenovaná knihovna je preferovaná díky úzké vazbě na Laděnku a dokonce ji najdete přímo v distribučním archívu.

Pro hnidopichy: pokud máte pocit, že prezentuji jako přednost něco, co je ve skutečnosti nedostatek frameworku, pak si prostě představte, že databázovou vrstvu frameworku tvoří Dibi a rozdělení do dvou samostatných projektů berte jen jako politické rozhodnutí.

Model tedy refaktoringu ušetříme, nikoliv však proto, že by to nepotřeboval, ale protože to seriál neposune dál.

Presenter

Na rozdíl od modelu nás u presenteru čeká pořádná práce. Jak už jsem naznačoval minule, reakce uživatele zhmotněná do odkazu může žádat o:

  1. změnu pohledu, presenteru nebo stavu (stavem je například hodnota parametru $money)
  2. vykonání příkazu (po vhození mince, stisknutí tlačítka)

Zapamatujte si důležitou zásadu: po vykonání příkazu by vždy mělo následovat přesměrování na další stránku. Nebo jinými slovy, URL žádající o provedení příkazu mohou být součástí HTML stránky, ale v adresním řádku prohlížeče by měly být jen URL určující stav. Po vykonání příkazového URL přesměrujeme na stavové URL.

Vezměme si automat na kávu. Pokud už v něm jsou 2 Kč a vhodím pětikorunu, tak prohlížeč zavolá příkazové URL:

  • index.php?money=2&do=insert&coin=5

ze kterého, jak káže moudré pravidlo, bychom měli přesměrovat na stavové URL říkající „v automatu je 7 Kč“:

  • index.php?money=7

Kdyby k přesměrování nedošlo, byl by to prohřešek proti logice HTTP protokolu, kde URL mají reprezentovat stav, proti SEO, neboť vyhledávač vidí stejný obsah na více rozdílných URL, a především proti použitelnosti. Do historie prohlížeče by se nám dostala adresa, po jejímž otevření, ať už tlačítkem obnovit nebo zpět, by došlo k nechtěnému vhození dalších mincí do automatu. Což zamrzí obzvlášť proto, že automat nevrací.

Nebylo by jednodušší generovat rovnou stavové URL? V tomto případě by to asi možné bylo, jsou ale situace, kdy to nelze. Představme si například katalog produktů řazených podle abecedy s odkazem na předchozí a následující položku. Zjištění konkrétního ID není úplně triviální a pokud by takových odkazů bylo na stránce hodně, mohlo by to aplikaci zbytečně brzdit. Stejně tak pokud se obsah katalogu často mění, nelze v době vykreslování přesně říci, který produkt bude při kliknutí na odkaz tím předchozím nebo následujícím. Odkaz proto bude lepší sestavit z ID aktuálního produktu s příkazem next nebo  prev.

Ale stále platí pravidlo o přesměrování. Jinak by se mohlo stát, že na e-shopu, kde nabízejí od šroubku po lokomotivu, si budete prohlížet produkt „záložní zdroj“, načež kliknete na odkaz „další produkt“ a dostanete se na „zdarma parfém Sergio Tacchini“. To je něco pro přítelkyni, řeknete si, a odešlete jí odkaz e-mailem a připíšete: Na tohle by ses měla vážně podívat! Bohužel půjde o příkazový odkaz, jako třeba index.php?id=zalozni-zdroj&do=next, a dříve, než se přítelkyně na stránku podívá, obchod rozšíří sortiment mimo jiné o přípravek proti „zápachu z úst“. Abecední řazení ho neomylně umístí ihned za záložní zdroj a zadělá vám tak na krizi vztahu. I kdyby to vaše polovička přešla, vy situaci znovu rozdmýcháte večer nevinnou otázkou: „Miláčku, dostala jsi ten e-mail? Co na to říkáš?“

K přesměrování slouží metoda redirect(), která se používá stejně, jako metoda pro generování odkazů link(). Takže upravíme metodu handleInsert tak, aby po provedení úkonu přesměrovala. A kam? To je dobrá otázka. Cílem bude aktuální stránka, aktuální stav a k tomu použijeme speciální slovo  this.

public function handleInsert($coin)
{
        // zvýšíme hodnotu vhozených mincí
        $this->money += max(0, (int) $coin);

        // po příkazu musí následovat přesměrování
        $this->redirect('this');
} 

Presenter a jeho pohledy

Řetězec this doslova znamená aktuální pohled. Až dosud jsme si vystačili s presenterem majícím jediný pohled a jedinou šablonu, jehož název byl default. Odsud třeba název šablony Machine.default.phtml složený z názvu presenteru, pohledu a přípony .phtml. Přesměrování na this je pak ekvivalentní s přesměrováním na  $this->redirect('default').

Kromě toho, že pohled určuje, která šablona se má zobrazit, zavolá Nette Framework také metodu render{NazevPohledu}(), kde je možné naplnit šablonu daty. V případě pohledu default by se tedy volala metoda renderDefault(). Její existence je přitom nepovinná.

Na řadě je refactoring metody handleBuy(). Navrhl bych následující postup: pokud se koupě kávy zdaří, přesměrovat na nový pohled coffee, tedy takové potvrzení objednávky. V případě neúspěchu nepřesměrovávat vů­bec.

public function handleBuy()
{
        $model = new Model;
        $result = $model->buyCoffee($this->money);

        if ($result) {
                $this->money = 0;  // vynulujeme částku (automat nevrací)
                $this->redirect('coffee'); // přesměrujeme na pohled coffee

        } else {
                $this->template->display = 'Málo peněz';
                $this->template->robots = 'noindex,noarchive';
        }
} 

Všimněte si, že odkazy na příkazy se od odkazů na pohledy odlišují vykřičníkem. Tj. $presenter->link('buy!') volá metodu handleBuy() (v rámci stále stejného pohledu default), zatímco odkaz $presenter->link('coffee') resp. $presenter->redirect('coffee') vede na pohled coffee. Po přesměrování se Nette Framework pokusí nejprve zavolat metodu presenteru renderCoffee(), která může naplnit šablonu daty, a poté vykreslí šablonu v souboru Machine.coffee.phtml. Protože taková šablona neexistuje, odpovědí bude HTTP chyba 404 – Not Found. Takže šablonu vytvoříme – bude zobrazovat kávovar s kelímkem hotové kávy, bez mincí.

Zbývá vysvětlit, proč v případě chyby přesměrování pomíjím. Je to totiž situace, kde opakování požadavku tlačítkem Obnovit je naopak vítané. Pokud byla chyba na straně automatu (došla voda), po jejím napravení lze objednávku zopakovat a zakončit úspěchem. Pokud by však došlo k přesměrování na stránku s chybovou hláškou, obnovení stránky by nevedlo k dalšímu pokusu provést transakci a přesto, že by se chyba na straně automatu vyřešila, stránka by stále zobrazovala tutéž již neaktuální chybovou zprávu.

Ačkoliv nedojde k přesměrování, doporučil bych stránku vyřadit z indexu vyhledávačů. Za tímto účelem jsem do šablony předal proměnnou  $robots.

Poslední úprava presenteru souvisí s tím, že už máme dva pohledy: default a coffee. V pohledu coffee nestojíme o to, aby se na displeji zobrazovala výzva k vhození peněz, kterou má na svědomí metoda startup(). Naplnění šablony daty proto přesuneme na vhodnější místo – do již zmíněné metody renderDefault().

public function renderDefault()
{
        if (empty($this->template->display)) {
                // na displeji zobrazíme celkovou částku nebo výzvu k vhození peněz
                $this->template->display = $this->money ? "$this->money Kč" : ('Vhoď ' . Model::COFFEE_PRICE . ' Kč');
        }
} 

Zazněly tu názvy metod jako startup(), handle{Příkaz}(), render{Pohled}()… nejvyšší čas se podívat na životní cyklus presenteru:

Životní cyklus presenteru

Životní cyklus presenteru

Netrapte se tím, že obsahuje celou řadu metod, které jsme zatím neprobírali. Dostaneme se k nim později. Teď je důležité pořadí, v jakém se jednotlivé metody volají (odshora dolů). Vidíte, že metoda renderDefault() se volá později, než handleBuy(). Protože v ní v případě neuskutečněné objednávky naplníme $this->template->display = 'Málo peněz', doplnil jsem renderDefault() o podmínku, jestli je proměnná display prázdná, abychom si ji nepřepsali.

Optimalizujeme pohled

Máme už dva pohledy a také dvě šablony Machine.default.phtml a Machine.coffee.phtml. Obě se přitom liší jen obsahem elementu <body>...</body>, zbytek je stejný. Protože kód by se neměl opakovat ani v případě šablon, přistoupíme k refactoringu spočívajícím v zavedení šablony layoutu. Tu uložíme do souboru @layout.phtml. Zavináč na začátku názvu slouží k přehlednému odlišení od šablon pohledů.

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <meta http-equiv="Content-Language" content="en" />
        <?php if (isset($robots)):?><meta name="robots" content="<?php echo $robots ?>"><?php endif ?>

        <title>Coffee Vending Machine in Nette Framework</title>

        <style type="text/css">
        ...
        </style>
</head>

<body>
        <?php $content->render() ?>
</body>
</html> 

V souborech Machine.default.phtml a Machine.coffee.phtml zůstane jen vnitřek stránky. Vloží se do šablony layoutu v místě volání  $content->render().

V podstatě jsme připraveni na poslední krok, a tím je slibovaná podpora AJAXu. Pokud se však podíváte na šablony, ruku na srdce, nejsou zbytečně moc ukecané a nepřehledné? Co byste řekli na to, kdybychom mohli místo zápisu:

<div id="machine">
        <p id="display"><?php echo htmlSpecialChars($display) ?></p>

        <a href="<?php echo $presenter->link('buy!') ?>"><img id="button" src="images/button.png" alt="Kup kávu" /></a>

        <?php if (isset($coffee)): ?>
                <a href="<?php echo $presenter->link('default') ?>"><img id="cup" src="images/cup.png" alt="Kelímek s kávou" /></a>
        <?php endif ?>
</div> 

používat raději něco přehlednějšího, úspornějšího a hezčího, třeba něco takového:

<div id="machine">
        <p id="display">{$display}</p>

        <a href="{link buy!}"><img id="button" src="images/button.png" alt="Kup kávu" /></a>

        {if isset($coffee)}
                <a href="{link default}"><img id="cup" src="images/cup.png" alt="Kelímek s kávou" /></a>
        {/if}
</div> 

Jak na to si ukážeme v příštím díle.

Zdrojový kód ukázek použitých v článku je k dispozici ke stažení.

Autor článku je vývojář na volné noze, specializuje se na návrh a programování moderních webových aplikací. Pravidelně pořádá školení pro tvůrce webových aplikací, vyvíjí open-source knihovny Texy, dibi a Nette Framework.

Refaktorujete často?

Komentáře

Subscribe
Upozornit na
guest
47 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
Anonymní

DAvid Grudl je totalny saso. clovek ktory si vytvara vlastny svet, clovek ktory sa nedokaze pressadit nikde inde, clovek ktory by v timovom projekte ktory bezi uz roky a dalsie roky bude bezat nikdy nedokazal presadit, clovek ktory je mimo, clovek co vymysla ulohy na urovni lahsich semestralnych zadani, clovek ktory si vymysli problem aby na neho napisal jedno z mnohych rieseni, trapos, ktory si mysli ze je genialny, ale pritom je to podpriemerny programator. Proste taky tutmacik, co ma 30 rokov, a zatial co it-ckari v jeho veku premyslaju nad tym kam vrazit tucne premie, tak on zobre o kazdu stokorunacku. proste „davidek debilek“ co sa strapnuje pred celym CS krajom, co sa prihlasuje na kadajeke mozne sutaze a webexpa lebo je presvedceny ze je genius. ;)

al

Tenhle generator jeste neznam, za pripadny link dik.

mekele

A ja si to uz davno rikal, ale nenasel jsem v sobe prezentacni potencial na vytvoreni podobneho shrnuti!
BTW, jake skoly/praxi je potreba mit aby clovek dokazal sesmolit neco jako tohle?

starenka

Nejaka nova verze slovenskyho Hulanatoru?

gawan

Prosím o zmazanie príspevku "saso pocmafrany", ktorý je vulgárny, urážajúci a porušuje elementárne pravidlá slušného správania, nič nové neprináša a znižuje úroveň diskusie na Zdrojáku. Nehovoriac o tom, že autor toho príspevku je zbabelec, ktorý sa ani nedokáže podpísať pod svoje slová. Možno preto, že nikdy nedokázal ani to, čo DG, keď má čas písať takéto primitivizmy. Podotýkam, že DG je mi celkom ukradnutý, nie som členom jeho fanklubu, ale uráža ma, keď musím čítať takého vulgarizmy na kohokoľvek. Zdroják považujem sa seriózny portál pre webových vývojárov a veľmi si cením prácu Martina Hassmana, ale chcel by som redaktorov poprosiť, aby si strážili kvalitu diskusií, aby bola zachovaná odbornosť a vecnosť a nebola zaspamovaná podobnými výlevmi zakomplexovaných primitívnych hulvátov. Potom môžete zmazať aj môj príspevok, lebo nič nové do odbornej témy článku neprináša. Ďakujem.

ja

1. Nemuzu si pomoct, ale "drzet" stav mincovniku a jednotlive akce resit pomoci GETu i pres tvoje argumenty mi prijde jako zhuverilost. Chapu ze je to pro priklad, ale…
2. Proc upravovat zobrazeni dat v controleru? Jednak pripadna lokalizace se bude hledat po celym kodu a jednak to nejde koncepcne moc dohromady pro vic moznych verzi zobrazeni(html, xml, json…). Jestli v tomhle spociva "presenter" tak uprimne fuj :P
3. K cemu htmlSpecialChars($display) – v te osekane sablone to snad probuh nedela automaticky ze ne?

v6ak

2. Celkem souhlasím – proč by se měl controler o to zajímat? View to může zobrazit obrázkem, poslat id přes JSON, …
3. Cože? Jak to chceš udělat? Něco ala magic_quotes_gpc? Pokud k 2. říkáš "fuj?", pak k tomto říkám "dvakrát fuj!".

mat

ad 3) viz http://nettephp.com/cs/quick-start-6
{$variable} => <?php echo htmlspecialchars($variable) ?>
{!$variable} => <?php echo $variable ?>
atd.

Anonymní

Add 2. Metoda renderXYZ(…) patří do pohledu (MVC neříká že kontroler musí být samostatná třída, ale že by se tyto činnosti měli oddělit. Jak to uděláš (a to záleží na konkrétním programátorovi) záleží na tobě.

v6ak

Myslím, že 2. odpovídá tomu, co jsem k tomu připsal – View si může zobrazit stav jakkoli, třeba obrázkem. Je tedy blbost, aby mu to Presenter diktoval. Nebo ne? Pokud se mýlím, rád bych z toho omylu byl vyveden.
U 3. jsem pochopil "osekané šablony" jako to bez projetí metodou CurlyBracketFilter::invoke. Právě proto jsem se proti tomu bouřil.
Naopak, pokud myslí "ořezanými šablonami" prostě tu kratší formu, pak můžu jen souhlasit, že se to dělá "samo".

v6ak

"Co se konkrétně stalo v článku v presenteru takového, že to "nejde moc dohromady pro vic verzi zobrazeni(html, xml, json…)"?"
Odpovím za sebe:
Například:
$this->template->display = 'Málo peněz';
V HTML může být výstup třeba Málo peněz, ale taky třeba JS, obrázek (no dobře, proti tomu lze něco namítnout…), může být potřeba měnit html třídu a další věci. Tato logika by se musela přesunout do Presenteru, kde mi nevoní – je to logika Viewu.
V XML by to mohlo být třeba <error id="not-enough-money"> a podobně v JSON.

"Navíc v dalším pokračováním dokonce dojde k záměně HTML za JSON."
Vyžaduje to manipulaci s Controllerem?
OT: "v dalším pokračováním" není správně – má být "v dalším pokračování". SRY za OT, ale uhodilo mě to do očí.

v6ak

"Řekl bych, že si děláš ve věci zmatek žonglováním s termíny controller, presenter, view a šablona."
Na tom asi něco bude.

"Neplatí, že hranice mezi částmi Model-View-Controller kopíruje hranici tříd" + "pro tento případ by bylo vhodné rozšířit API o příznak chyby nebo chybový kód"
Někdy je to IMHO vhodnější. Nevoní mi přidávání nějakého stavového kódu v Presenteru nebo Controlleru (tady je to jedno, ne?) jen kvůli tomu, že to chce View?
Pokud to chápu, tak tady se přesouvá část View do Presenteru, aby místo celého View byla šablona.

"nebylo tomu tak ani v tzv. klasickém MVC"
Proti této argumentaci lze použít citaci z http://zdrojak.root.cz/clanky/nette-framework-mvc–mvp/ : "Historický exkurz měl ukázat, jak různorodé bylo pojetí MVC už v okamžiku vzniku. Byla to holt doba pionýrská. Nechápejte proto MVC dogmaticky!"
Pokud jde jen o nějaké "mimochodem", pak budiž.

v6ak

No já si teď neumím přesně představit ty problémy, i když možná tuším – počkám, až ukážeš komponenty a pak to rozeberu.
Přiznám se, že Nette se mi původně zdálo divné, ale vypadá to, že všechny ty divnosti mají svůj účel a logické opodstatnění.
A na klasické MVC bych se neodkazoval, když mluvíme o současnosti…

ja

2. Myslel jsem přesně to co psal v6ak. Přeci i tak pracuješ v šabloně s logikou (isset($coffee)), proč tedy mít logiku na dvou místech? …to není problém frameworku, jen mé pragmatické smýšlení nechápe proč to dělat takhle, když to víc věcí komplikuje…
3. Pokud existuje i varianta {!…} tak samozřejmě ok, jen se chytám toho, že ze spousty "automatických" featur zvětšiny pro začínající "programátory" při pokročilejším programování smrděly problémy.

yeah

Spíš než návrh ti napíšu jak to funguje v Symfony. Má taky svoje nevýhody, ale řekněme že funkční kód od šablony odděluje imho velice dobře.

1. Má sloty, což vypadá asi takhle:
layout:
<meta name="robots"><?php if(!include_slot('robots')): ?>index,archive<?php endif; ?>" />
a v html šabloně erroru:
<?php slot('robots', 'noindex,noarchive') ?>

2. Má komponenty a helpery. Šablona komponenty Display (sf_user je v šablone obal okolo session, v akci je pod $this->getUser()) includovaná do layoutu:
<?php echo $sf_user->hasMoney() ? format_currency($sf_user->getMoney()) : __("Insert coins") ?>

3. A z akce v controleru ti zbyde např. jenom
executeBuy() {
if(!$this->getUser()->buyCoffie()) return sfView::ERROR;
}

Ve finále máme čistej controler, logika html šablon je čistě v šablonách, můžu si navymýšlet šablony pro xml i json aniž bych musel šáhnout do "funkčního" kódu.

yeah

No, můj způsob práce je co nejvíc oddělit formu zobrazení a kód, který manipuluje s objektama před zobrazením(ať už tomu říkáme jakkoliv) abych si mohl se šablonama dělat co chci a v kontroleru mi zase nerušily řetězce. Ty budeš takhle asi vždycky vázán na presenter, který s jinou formou prezentace budeš muset měnit. Já si v routování akorát nastavím "koncovky" šablon – a mám z výstupu instantní rss, json atd. Jestli správně hádám tak ty vytvoříš buď další presenter(opakující se nebo nadbytečný kód) nebo budeš nastavovat šablonu podle nějaké proměnné(budeš směšovat kód pro různé šablony)…

Nicméně máš pravdu, s kodérem to budeš mít mírně jednoduší ty, já bych teda z nich nedělal přímo cvičené opičky…s lehčí nápovědou taky lecos pochopí :)

llook

To, co se v Symfony nazývá akce, je v Nette rozdělené na akci a view. Metoda renderDefault patří k view a plní obvykle podobnou funkci jako Code Behind v ASP.NET (prostě věci, které se člověku nechce dávat do šablony, ale přitom je to pouhá prezentační logika).

Pokud by k akci chtěl přidat další view, tak by přidal pouze další renderNěco metody, ve kterých by si data upravil pro jiné šablony (při použití push šablon), kód samotné akce by se neopakoval. Akorát by teda do akce musel přidat nějakou logiku pro výběr view, třeba na základě parametru z routy, např:

public function actionDefault($view = "default")
{
    // Logika akce, tj. controlleru
    // ...

    if (in_array($view, array("default", "rss"))
    {
        $this->view = $view;
    }
}

Viz http://nettephp.com/cs/action-vs-view

Baset

Chtěl jsem se zeptat, v jakém SW vznikl "Životní cyklus presenteru" – tedy obrázek: http://i.iinfo.cz/urs/nette-401-123844392320589.gif ?
Experimentoval jsem s ArgoUML, ale to tak hezky nestínuje.
Omlouvám se za OT k tomuto článku.

Abraxis

Podobne obrazky lze relativne snadno tvorit v OmniGraffle (Mac-only, sorry ;-)) – velmi doporucuju.

Anonymní

Pan Grudl, prestante bojovat s veternymi mlynmi ;-), skuste sa pozriet na http://ics.upjs.sk/~novotnyr/java/spring/spring-mvc.pdf Mozno tam najdete odpovede na mnohe svoje otazky. S pozdravom uspesny konverter zo sveta PHP do sveta Javy. ;-)

Roman

Ak náhodou nie si nejaký geroj, čo sa zamestnal v nejakej firme, berie pravidelne plat za to že obetuje svojmu zamestnávateľovi X hodín zo svojho bezvýznamného programátorského života tak by tento tvoj komentár mohol mať aj nejakú výhu, v opačnom prípade músim skončtatovať, že je podstatný rozdiel medzi životom robotníka v kompromise a životom človeka ktorý „riadi“. Hlavne je tak trochu trápne mu dávať nejaké rozumy. Ja osobne mám väčší rešpekt voči ľuďom ktorí sa nad vecami zamýšľajú a rišenia prinášajú ako nad tými ktorí ich „iba“ akceptujú.

S týmto súvisí aj môj obľúbený citát o (priemyselnom) dizajne. „Design is about how something works, not how it looks. It's what's inside that counts.
The best designs are the result of someone's questioning everything around them.“ (James Dyson)

Treba sa občas snažiť aj o veciach premýšľať. Nie sa na ne iba slepo adaptovať. Hlavne v prípade ak človek chce niekam pokročiť vo vývoji.

Anonymní

Lenze to vobec nie je o tom, ze sa nad niekym chcem vyvysovat. Pan Grudl je urcite inteligentna ludska bytost a snazi sa optimalne riesit problemy suvisiace s tvorbou webovych aplikacii. V PHP som programoval zhruba tri roky a takisto som si naprogramoval spustu kniznic, ktore mi v danej chvili riesili problemy – a na druhej strane vytvarali nove. S casovym odstupom mozem tvrdit, ze som vtedy programoval dost s klapkami na ociach. Budete sa divit ale prave konfrontovanie s pracou inych ludi ma posunulo niekam inam. Ono je totiz rozdiel vymyslat aplikaciu , ktoru bude programovat jeden clovek a za mesiac sa odovzda, objedna sa cez nu par objednavok na nete a po pol roku domena zanikne. Studoval som framework pana Grudla, nette aj dibi, avsak pri vsetkej ucte si dovolim tvrdit, ze nie je vobec vhodny pre timovu pracu na projekte ktory trva roky a na ktorom spolupracuje desat dvadsat programatorov. A o tom to je, naco vymyslat mini pidi frameworcok, bez ambicii aby prekrocil tien miniwebiku, ktory je one man show? Zrejme ste si len potrebovali slovne ulavit, alebo mate stereotypnu predstavu o tom ze timova firemna praca programatora spociva len v bezhlavom prijimani prikazov od skusenejsich programatorov a lepenie kodu len aby fungoval. Divili by ste sa kolko toho vasho hlbaveho premyslania na dizajne sa v takomto projekte vyskytne. ;-)

Jiří Knesl

Každý framework se hodí na něco jiného. Že se podle Vás nehodí Nette na projekt na 30 člověkolet, to je docela dobře možné. Uvědomte si ale, že takových projektů je ze všech vznikajících webů sotva půl procenta (Zdroj: vycucáno z prstu).

Nette může být naopak mnohem lepší/jednodušší/snažší na údržbu a na kvalitu zdrojáků pro 80 % projektů.

Nechci a nebudu tady kopat ani do Springu, ani do Nette. Každý framework má to svoje. A brečet, že se assembler nehodí na kódování webu a ruby na programování operačních systémů (nadsázka), to je prostě zcela mimo.

Anonymní

Zopar poznamok.. je kopec zle urobenych projektov (ci uz je to pidi projekt alebo enterprise solution) ktore funguju a zarabaju peniaze cele roky.. a je jedno ci ich robi velka alebo mala firma.. to vedia vsetci co robili vo velkych aj malych firmach. Nejde totiz o to na com sa to robi, ale presne o to hlbave premyslanie, o analyzu, riadenie projektu a ostatne hovadiny. Je fakt jedno ci je to one man show alebo velky projekt, pre to ci projekt bude mat navratnost alebo ustoji svoj rast to nie je absolutne podstatne. Najviac sa mi pacia vsetky tie korporacie co sa snazia po mesiacoch usilia na webe pretlacit svoje portaly a smejem sa ked to ich sefstvo zasa po mesiacoch zaklincuje pretoze to nefunguje a potom sa pozries kusok vedla kde na kolene niekto zbuchal nejaku somarinu ktora zaraba miliony dolarov rocne. A potom pride nejaky mudrlant a zacne rozpravat nieco o timoch a jedinom uzasnom skvelom frameworku. ;-) To je ta relativita.

Kazdopadne. Myslim ze si ma uplne presne pochopil. To mi staci, netreba riesit. Kludne si uzivaj svoj jednoduchy zivot a povazuj to za spravne rozhodnutie vo svojom zivote. Mozno je to naozaj to spravne rozhodnutie. Zamestnat sa, mat pravidelny prijem, postavit dom zasadit strom, postarat sa o rodinu. Kazdy je strojcom svojho osudu. Niektori si budu pidizlikat nejake smiesne vlastne riesenia a trpiet cely zivot.. mozno z toho nic nebude.. ale pre pokrok je to rovnako dolezite ako udrzanie rodu. ;-)

Aleš Roubíček

Přece jen segment menších webů je celkem velký na to, aby i pro nějmohli existovat frameworky, ktere jejich vyrobu zefektivní. Na ty velke tu jsou pak pracanti jako vy.

v6ak

To bylo celkem trefné. Stejnětak, dohnáno do extrému, pro víceméně statické stránky obsahující kontakt, otevírací dobu a základní info bude MVC spíš zbytečné zdržování. Dynamické stránky se mohou použít tak nanejvýš na jednoduché šablony pro kostru stránky. Nette je zde sice asi použitelné, ale spíš zbytečné.
Podobně nelze Spring cpát kamkoli…

David Grudl

Cele PDF jsem poctive precetl a prekvapilo (a samozrejme povzbudilo) me to, ze je to Spring MVC, kdo by se mohl od Nette hodne ucit. I kdyz je otazka jak moc je ten dokument vypovidajici, protoze treba o MVC jsou tam velmi chybne informace. Ale nechci se prit, kdo je nebo neni lepsi, je to proste muj dojem.

Anonymní

Vas pri citani Spring MVC prekvapilo ze by sa mohol od Nette ucit? A kde ste na to narazili, mozno som prave ten slajd preskocil, ked to tam bolo uvedene. Nuz neviem, skromnosti zrejme nemate na rozdavanie. Tvrdit ze Spring – celosvetovo rozisreny od pidifiriem po korporacie sa moze od vas ucit. Zeby nova konkurencia pre Roda Johnsona? ;-)

roman

namiesto nekonkretnych blabolov by ste obaja mohli prejst k samotnemu boxu.. teda ak je na to vola.. prednost by mohol mat obhajca springu.. nech sa paci ;)

Anonymní

Spring je v URL zviazany v dvoch oblastiach:
——–
* Sufixy URL adries su uvadzane v anotaciach pre kontrolery.
Tohto sa mozno alebo napisanim vlastneho mapovania requestov na kontrolery, ktory moze byt taky dynamicky ako sa ziada a jednym riadkom ho deklarovat v XML.

Nette adresy generuje plne dynamicky. Ak som pochopil spravne, tak trik spociva v pritomnosti premennej $presenter, ktorej metody vygeneruju URL. Vyzera to ako dobry napad, pretoze naozaj sa zbavite URL adries vo view vrstve.

Ale: Spring MVC absolutne neriesi, v com bude napisany view. JSP? Freemarker? JasperReports? RSS? Staci, ze view rendered dostane modelovu mapu a ako ju zrenderuje je na nom. Nette podporuje primarne PHP, ako je to s inymi vrstvami?

* Modelom moze byt lubovolna trieda. Myslim, ze uz po Struts 1.x sa ludia poucili a zistili, ze nema zmysel, aby model musel byt nieco specialne. Automaticke vkladanie navratovych hodnot do modelu je super vec. Tu sa zhodneme

* Kontroler. Spring MVC razi zasadu, ze obsluzne triedy maju byt jednoduche, najlepsie bezne triedy s anotaciou. (Anotacia je ekvivalentna marker interfacu bez metod).

* Mapovanie nazvu view na konkretnu implementaciu je riesene jednym riadkom v XML.

* Odkazovanie. "redirect:" je skratka pre pohodlnych. Pokojne mozete vratit specialny RedirectView, kde uvediete logicke meno viewu a model (presny ekvivalent "->redirect()"). Alternativne mozete view do kontrolera zadrotovat cez dependency injection a kontroler ani nebude tusit, ze nejaky redirect sa deje.

Tu by som podotkol, ze netreba mat totalnu paranoju z XML. Bezna springova aplikacia ma aj tak XML subor pre dependency injection, cize tam je to jedno (a pozor: DI je velmi dobry pattern, ktory vyvoj velkych aplikacii sprehladnuje).

////////////////////////////////////////////

Inak som velmi poteseny, ze vidim nejaky slubny MVC framework pre PHP. PHP si ho zasluzi.

Mam len otazku:
* ako sa riesia ine formaty view? (Vid vyssie)
* ako je mozne pouzivat vlastne formulare (Nette generuje kod formularov dynamicky, toto Spring MVC nema, view vrstvu nechava na vyber implementatora)

Robert Novotny

To hore som ja :-)

Este mi napadlo: ktore vlastnosti by vam chybali?

Mna primarne zaujalo to generovanie formularov spolu s JS validaciou. To vyplyva z generovania formularov cez PHP.

Anonymní

Nechcem liat ohen do ohna v debate "PHP je pre lamy, Java rulez!", pretoze ta je uplne zbytocna.

Prezentacia (ktorej som zhodou okolnosti autorom) pokryva ,,highlights" zo stylu vyvoja Spring MVC, ktory je zalozeny na konvenciach a anotaciach. Paralelne s nou existuje ,,stara" moznost, kde su konvencie vymenene za XML konfiguraciu. Ale zakladna filozofia ostava taka ista.

V ktorych konkretnych bodoch vidite vyhody Nette oproti Spring MVC? (Prirodzene, su to dva rozlicne frameworky pre dva rozne programovacie jazyky.)

proboha

pane, prosim vas budte tak laskav a odeberte se zpet do maroka, ano?

Srigi

Poctivo prechadzam serial a coraz viac dochadzam k nazoru, ze Nette mi nebude sediet ( co je obrovska skoda, veci ako Object alebo Ladenka su genialne). Vadi mi MVP paradigma, ktore Nette pouziva.

V tejto casti sa definoval novy view, ale bohuzial ked kukam na kod presentera, nedokazem z kodu „handle“ fnci urcit co sa bude renderovat. Vadi mi, ze v app je viac Views a napr. ked pozeram na kod handleInsert() nedokazem povadat co sa bude diat po zavolani $this->redirect(‚this‘) – co sa vykresli.

Ako uz hore niekto pisal, spojenie logiky P a V nie je good. A skutocne. Prechadzam aj ten diagram, ale nie som schopny urcit, kde a aky View sa pouzije.

V ZF je toto IMO omnoho logickejsie. Je jediny View. A na zaklade dispatchingu sa vykona nejaka akcia a k nej zdruzena sablona sa preda do toho jedineho View. Velmi podobne je to v Symfony.

Srigi

Aha, pozeram, ze aktualny view je mozne odvodit zo sablony pomocou tych (ne)vykricnikov v odkazoch $presenter->link().

Froyo

Hodilo by se, kdyby byl na konci zobrazen vždy nějaký ucelený kod nebo možnost stáhnout kompletní projekt. Někdy se ztrácím co je model,presenter a o jaký presenter se jedná.

nemesisqo

asi to je otazka odveci a ani niesom niejako zvlast dobry v kodeni no ale stala sa mi taka veci zmenil som subor model v dokoncenom projekte teda ked som ho robil sam neslo to ladenka mi davala chybu :InvalidState­Exception
Cannot set HTTP code after HTTP headers have been sent (output started at /domains1/do2538000­/public/www_ro­ot/CoffeeVendin­gMachine/app/mo­dels/Model.php:1).
akvsak zlvastne je natom to ze:1, prava su ake maju byt,
kodovanie suboru je utf8
zmena bola napr z const COFFEE_PRICE = 10; na const COFFEE_PRICE = 30; staci ze znamem 1 a dam 3 a uz je to tam ladenka to hodi a ak prekopirujem z povodneho rozbaleneho projektu subor model.php uz to ide a potom znovan napr len zmazem a s5 napisem 1 aby akoze prebehla zmena v subore a ladenka hodi tu chybu, prosim vas mozete mi niekto stym pomoct o co tu ide? budem fakt vdacny a ospravedlnujem sa ak to nieje vhodne vzhladom na temu alebo je to hlupa utazka.

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.

Pocta C64

Za prvopočátek své programátorské kariéry vděčím počítači Commodore 64. Tehdy jsem genialitu návrhu nemohl docenit. Dnes dokážu lehce nahlédnout pod pokličku. Chtěl bych se o to s vámi podělit a vzdát mu hold.