Autor Zpráva
han5vk
Profil
Zdravím, staviam si vlastný "RS", mojú prvú poriadnejšiu aplikáciu v OOP, pričom (aspoň sa snažím) používam MVC architektúru. Momentálne to je v podstate tak, že nejaký hlavný controller podľa parametrov GET určí, aký controller má vlastne pracovať, a potom na ňom zavolá metódu work(), kde si už každý controller zisťuje sám čo sa po ňom chce, a volá svoje privátne metódy, či metódy modelu. A tu je ten problém, vezmime si príklad, chcem zobraziť výpis článkov v kategórii. Front controller zavolá CategoriesController->work(), ten zistí že nechcem kategóriu ani zmazať, či upraviť, ale vypísať jej články.

1, Má sa teraz vytvoriť nový objekt nejakej triedy Category, ktorý bude mať všetky vlastnosti rubriky z DB, a bude s nimi vedieť pracovať, pričom volať jeho metódy bude daný controller, ktorý následne dáta vypíše cez view, alebo
2, mám mať nejakú všeobecnejšiu, povedzme statickú triedu pre tieto kategórie, ktorá bude vedieť úplne všetko, a nebude obsahovať dáta vyťahané z DB?

Toto nie je asi najlepší príklad, ale predstavme si, že ide o používateľov. Trieda User bude obsahovať len jedného, čo ak ich potrebujem všetkých vypísať? Potreboval by som asi nejakú továreň, čo by ich dokázala vypisovať, mazať, robiť štatistiky, či?

prvé riešenie by mi prišlo lepšie, keby som dokázal uchovávať jeden objekt rubriky, pokiaľ s ňou pracujem, a nepotreboval by som tento objekt pri každom refreshi vytvárať. To je ale blbosť sama o sebe.

ďalej som zatiaľ nasledovné veci spravil takto, ocenil by som ak je niečo zle aby ma niekto upozornil:

3, mám len jednu triedu view, ktorá ma len jednú inštanciu (bože to je divné slovo...), a tú zdieľam každému controlleru v konštruktore
4, controller dostáva objekt view a parametre (napr. z GET) , z ktorých zisťuje čo sa po ňom vlastne chce
5, controllery nastavujú aké druhy šablón sa majú načítať a s akými dátami (neuvádzam priamo názvy súborov, kvôli lepšej organizovanosti a aby sa dali zmeniť centrálne, len raz)
6, objekt view si tieto dáta a druh šablóny uchovávajú až do skončenia práce controllerov, a následne ako posledný krok sa vypíšu, preto aby som vedel aj v controlleri čo sa spustí nakoniec nastaviť iný title stránky, či zobraziť chybovú hlášku ešte pred obsahom, prípadne ak skript skončí nejakou fatálnou chybou, aby sa mi stránka nezastavila v polovici, až k chybe dôjde, ale vedela o nej než sa začne vypisovať, a zobrazila niečo iné.
7, chyby v controlleri či modeli hádžu výnimky, pričom napr. pri zadaní nevalidného mena do registračného formulára sa táto exception odchytí v controlleri registrácie, ak dôjde k inej chybe, ako chýbajúca šablóna, neznámy parameter v GET (alebo že škrečky lietajú), tak sa výnimka hodí ešte vyššie, a odchytí ju frontcontroller, pričom chyby ako aj všetky hlášky potom vypisuje zo slovníka typu "e200" -> "fatálna chyba" to číslo za e predávam ako number code Exceptionu -- v celom tomto bode som najmenej presvedčený o správnosti...

Čítal som toho dosť, hľadal, a všade sa isté veci rôznia a som z toho magor. Nechcem nakoniec postaviť celú aplikáciu a potom ju prekopávať, lebo som niečo nepochopil. ďakujem
tiso
Profil
OT: prečo si vlastne píšeš vlastný framework? Ak je to kvôli učeniu sa, viac sa naučíš keď budeš pracovať s niektorým dobrým, s existujúcich zdrojákov. Skús si ich prezrieť viac. Problém je, že ako začiatočník nebudeš vedieť rozlíšiť čo je dobré a čo zlé.
han5vk
Profil
Píšem si to preto, lebo si to písať chcem. Nemám rád, ak používam niečo čomu nerozumiem, čo som sám nenapísal. Ide mi o to, pochopiť celú štruktúru, a vedieť ako sa to vlastne dá robiť. Ak to čo vznikne nebude stáť za nič, alebo budem tráviť veľa času nad triviálnymi vecami čo by mohol vyriešiť nejaký framework, tak sa na to vykašlem a spravím to s ním. Nechápem ale, prečo by každý mal používať nejaké to Nette či Zend alebo niečo iné, ako keby to bola nutnosť. Dajú sa tvoriť javascripty bez jQuery, dá sa spraviť aj vlastný framework, tak neviem prečo všade toľkí Ľudia vravia ostatným, že bez cudzieho FW sa nezaobídu. Avšak, možno len niečomu nerozumiem... Každopádne "použi nejaký framework" nie je odpoveď akú by som čakal na moje otázky. Ajtak, ďakujem.
Tori
Profil
Na téma FW obecně: taky jsem dřív používala cosi vlastního. Ale s každou běžnou věcí (posílání e-mailů s přílohami, práce s obrázky, galerie, upload...) jsem se musela rozhodovat, jestli tvořit něco vlastního (s nejistým výsledkem) a pak ještě pár měsíců náhodně objevovat chyby, nedostatečné funkce, apod., anebo jestli stáhnout hotovou komponentu a strávit řádově kratší čas jejím začleňováním do FW. Po několika projektech (včetně nedokončených) už se mi přestalo chtít věnovat tomu tolik času a přešla jsem k hotovému. Někomu to stojí za to, experimentovat s vlastním FW třeba půl roku, někomu jinému x let, ani jedno bych neřekla že je špatně.

Ad 1) - to nemá být hlavní kontroler, ale router. Teda třída (soubor tříd), která má na starosti překlad URL na kontroler+akci a vytváření URL podle zadání kontroler+metoda (pokud je to obousměrný router). Rozdíly v přístupu jsou např. v tom, kdo volá akci kontroleru - jestli router volá pro všechny požadavky Application->run() a dohledání + volání správného kontroleru a view nechá na Application, anebo jestli se to řeší ještě v Router->delegate(). K ostatnímu vám neporadím, málo vím.
han5vk
Profil
Tori:
Ak som pochopil Ad 1 , tak Router (u mňa vlastne len zle pomenovaný FrontController), má podľa parametrov v URL zistiť aký Controller a akú jeho akciu zavolať, teda nejako takto-

1, dostanem URL napr. www.foo.bar/categories/show/android
2, Router zistí, že mám 2 parametre, prvý je určený ako názov controlleru, druhý ako akcia čo sa má vykonať, a všetky ďalšie sú parametre pre Controller aby vedel, s čím má pracovať
3, Router zavolá daný controller, a v ňom danú akciu, pričom jej predá ostatné parametre
4, controller pracuje s view a modelom atď...
5, používateľ dostane výpis kategórie "android"

?
Takže router by mal vlastne volať akcie controllerov a checkovať koľko má parametrov? Lebo doteraz som to mal nejak tak, že každý Controller si po spustení zistil, či má zadanú nejakú akciu pri kategórii, ak nie tak ju vypísal (články v nej) a ak áno, tak robil niečo iné.

Ospravedlňujem sa, ale veľmi nechápem čo znamená všetko to Application->run(), či Router->delegate(). O čo sa vlastne stará tá trieda (alebo objekt) Application?

Inak, privítal by som možno aj od iných nejakú tú odpoveď na ostatné otázky, teda ak nie sú až príliš začiatočnícke, v tom prípade by bodol nejaký odkaz, alebo kľúčová fráza čo hľadať. Seriálov o OOP (či MVC) v PHP som prečítal asi 5, všade je to trocha inak, a nikde nie je úplne všetko.

Ďakujem
martin1312
Profil
Ešte by si mal počítať s tým, že budeš potrebovať použiť aj vlastné route pravidlá (čisto iba ako príklad uvediem nasledovný zápis):
$my_rule['prihlasenie'] = 'user/login';
Teda pri URL www.foo.bar/prihlasenie sa v pozadí vykoná ako www.foo.bar/user/login
han5vk
Profil
martin1312:
Nad týmto som rozmýšľal pri prechádzaní Zendu, router by mal byť dostatočne konfigurovateľný z nejakého Array config súboru, pričom sa určia základné pravidlá, čo je označenie controllera, čo akcie, čo paramatrov, s tým, aby sa to dalo kedykoľvek v budúcnosti zmeniť len prepísaním configu. Samozrejme, dajú sa určiť výnimky. Nechápem ale, v čom je lepšia adresa www.foo.bar/login (kde by som musel obchádzať pravidlá) od www.foobar/users/login (kde nemusím riešiť výnimku a natívne mi to spracuje UsersController) ? Samozrejme, jazyk nie je problém prepísať, resp. pri rôznych jazykových verziách prekladať.
Tori
Profil
han5vk:
veľmi nechápem čo znamená všetko to Application->run(), či Router->delegate().
Tím jsem jen chtěla říct, že jsou různé přístupy k tomu, do čí zodpovědnosti patří volání controlleru + nastavení a volání view, a taky ověřování jestli požadovaný controller existuje a ošetření chybových stavů. Podle toho, do jaké míry je router vzájemně závislý na zbytku FW.
1. Buď to může patřit do zodpovědnosti routeru, který musí vědět, že pro URL /user/login volá UserController->login() a pak třeba UserController->view->render() a v případě chyby ErrorController->error($nejakyChybovyKod), anebo
2. router jen vytvoří instanci třídy Application, předá jí parametry z URL (controller, action) a o víc se nestará. Application si pak natáhne další parametry z URL (např. ID článku), vyhledá správný controller, předává ID, volá view, zachytává nečekané výjimky a chybové stavy.
polonium
Profil
han5vk:
Smyslem toho co psal [#6] martin1312 jsou hlavne hezka url. Zkusme jiny priklad. Rekneme ze mas blog a v nem clanek "Jak na hezka URL".
Bud se k tomu clanku muzes dostat takhle:
example.com/jak-na-hezka-url
nebo
example.com/article/123-jak-na-hezka-url
nebo
example.com/article/123

Ne vzdy se ti muze hodit mit nazev controlleru nebo action v url. Hlavnim ukolem routeru by melo byt pochopeni url, kterou dostane. Tedy, ty mu na vstupu das /jak-na-hezka-url a on ti vrati treba:
array(
presenter => Articles,
action => show,
id => 123
)

A navic, skvela vec je kdyz controller umi spolupracovat s routrem treba kdyz vytvaris url. Zavolas jen Controller->link("Article", "show", array("id"=>123)); A jelikoz ma router preddefinovane routy, tak ti vrati /jak-na-hezka-url.

Application->run(); by melo byt neco co da zivot tvemu controlleru, vlastne by to melo byt neco co ridi jeho zivotni cyklus. Pred Application->run(); se provede cinnost routeru, takze vis co se bude dit v run(). Vytvorit instanci controlleru, predas mu request, zavolat action, pak mozna render a pak to vsechno plivnes do browseru.

btw kdyz jsem zacil s psanim webu, tak jsem taky neveril nicemu co jsem si nenapsal sam. Asi to bylo tim, ze jsem tomu neumel nahlidnout pod poklicku. Ani nette jsem nezacal poradne pouzivat driv nez jsem mu prolez zdrojak a neprocet dokumentaci :D

Samozrejme pointa je Proc vynelezat kolo, kdyz uz mame trakar, ale na necem se to naucit musis, ze :)


[#1] han5vk

ad 2 vyvaruj se statickym tridam :) Existuji elegantnejsi zpusoby. To co popisujes zarizuje model, vypisovani uzivatelu je jeho prace.
class UsersController
{
  public function actionShowUsers()
  {
    $users = $this->getModel("users")->getListOfUsers();
  }
}

ad 3 mozna je zbytecne predavat instanci view primo, jelikoz se muze stat, ze se ani nedostanes k renderovani stranky. Lepsi vytvaret instanci view az ve chvili kdy ji skutecne potrebujes.

Napr. odesles registracni formular, actionRegMe vytovri noveho uzivatele, ale kdybys rovnou napsal na stranku "Dekuju za registraci, bla bla.." Uzivatel stickne F5 a odesle form znovu a pak znovu a znovu... V tomto pripade je tedy lepsi provest action a hned presmerovat na jinou stranku.

ad 5 kde v controlleru resis nastaveni sablony pro view?
ad 6 jak view pozna ze controller skoncil a tedy, ze muze zacit renderovat?
han5vk
Profil
polonium:
Tiež som rozmýšľal nad takýmito adreasami, ale ako mám zistiť či sa snažím zobraziť nejakú tú rubriku, článok alebo používateľa? Čo ak sa rubrika bude volať čo ja viem, 'Android' a nejaký používateĽ si bude tiež chcieť zaregistrovať takéto meno? Čo sa udeje pri URL foo.bar/android ?

ad 2, myslel som to skôr tak, či mám pri výpise článkov z DB pre každý článok samostatný objekt, v nejakom cykle napríklad, a s tým potom pracovať, alebo si len do nejakého jedného veľkého objektu natrepať všetky články a na ňom potom volať akcie na vypísanie

ad 3, asi ti nerozumiem, ale veď to, že sa vykoná akciaRegMe v nejakom UserController, ktorý má predaný view, neznamená že sa niečo nevyhnutne bude zobrazovať. RegMe len overí dáta, vytvorí usera, a presmeruje niekde na index, kde zobrazí hlášku o úspešnej registrácii (a možno prihlási používateľa), samozrejme, nebude robiť všetko sama, použije nejaký validátor, nejaké dátové rozhranie na vloženie usera a router na presmerovanie.

ad 5, išlo mi o to, že nechcem volať niečo ako $view->render("registrate.phtml",$data);, pretože ak by som chcel zmeniť názov šablónových súborov, či štruktúru súborového systému, bolo by náročné prechádzať všetky triedy a upravovať to. Myslel som to nejak tak, že by sa zadalo "registrate" a nejaký config súbor by mal na starosti mapúovanie názvov súborov, priečinkov, či prípon. Ajkeď vlastne neviem, ako to technicky spracovať. Poradí niekto?

ad 6, tiež asi nerozumiem otázke. Myslel som to nejak tak, že keď sa budú napr. odchytávať výnimky v controlleri, tak v bloku finally sa ako posledný príkaz jednoducho zavolá $view->renderPage(); alebo niečo podobné.
polonium
Profil
ad 3 to je přesně ono, né vždy se bude něco zobrazovat a právě proto je zbytečné předávat view constructoru. Dokonce je lepší když některé action nemají výstup, viz znovu odesílání formulářů. Napsal jsem to trochu kostrbatě v předchozím příspěvku :)

ad 5 strukturu phtml souborů, můžeš řešit třeba takto:
controller = user
action = registrate
templates/user/registrate.phtml

a pokud nebudeš chtít pro action registrate soubor registrate.phtml můžeš použít třeba $view->setLayout('regme');

ad 6
han5vk:
objekt view si tieto dáta a druh šablóny uchovávajú až do skončenia práce controllerov
Jo vyjímky jsou jedna věc a jak při běžném spracování request view pozná, že controller skončil a může začít renderovat?
han5vk
Profil
Ad 3, teda ja fakt neviem, ako toto sa ma riesit. To si ma kazda akcia vytvorit novy View, a potom nim renderovat, alebo ako? Doteraz som to bral tak, ze do view controllery poslu do View data a sablony a az nakoniec celeho skriptu view.vyrenderuje celu stranku. Ako inak sa toto riesi ?

A ako je to teda s tymi URL ? Pouzitie bez nazvu controllera mozem pouzit len pre.jeden controller, napr. Rubriky. Co inak, ak chcem zobrazit profil pouzivatela, ktory bude mat rovnake meno ako nazov clanku ci rubriky ?
Tori
Profil
han5vk:
Co inak, ak chcem zobrazit profil pouzivatela, ktory bude mat rovnake meno ako nazov clanku ci rubriky ?
Čekala bych nějakou odlišnou URL pro články a profily uživatelů. Např. /uzivatel/fantomas nebo /~fantomas (uživatel) vs. /fantomas (článek). Jako uživatelce by mi připadalo dost divné, abych nemohla dát článku nadpis jaký chci kvůli tomu, že nějaký uživatel (ne článek) už se tak jmenuje.
han5vk
Profil
Tori:
No, to mi je jasné, bola by blbosť povedať "Hej, nemôžeš takto nazvať článok, pretože škrečok na druhom konci planéty sa volá rovnako !" :) Narážal som na to, že polonium navrhoval vypustiť názov controllera (article) z URL. Musel by som zmeniť všeobecné pravidlá routovania (/controller/action/param1/param2...), pričom sa to dá využiť len na jeden controller, teda že by som mal síce články bez toho /article/show/, ale rubriky či používateľov by som musel ajtak explicitne písať do URL ako /users/show/fantomas a podobne. Rozmýšľam však o tom, že ak nemám zadanú action (method_exists($controller,$action."Action") ?) tak sa defaultne spustí show(), teda zobrazenie článku, rubriky, či profilu používateľa.
Tori
Profil
Většinou je možné mít těch pravidel více. Např. (používám metaznaky pro PCRE):

/users/.+   => /:controller/:username + action=showProfile
/.+/.+/.*?  =>  /:controller/:action(/:parametr)?
/.+  => /:url_clanku + controller=clanky + action=show
... apod.
Takže by se neměnila pravidla routování, ale přidalo by se nové pravidlo pro nějakým způsobem specifikovanou URL.
han5vk
Profil
Takto nejak som to myslel. Ako ale riešiť neznámy počet parametrov, 0,1,2,5,10... ? To pre každú možnosť budem prídavať nové routovacie pravidlo?
Tori
Profil
A všechny ty parametry jsou nezbytně potřebné k výběru správného kontroleru a metody? IMHO by stačilo jen určit, které jsou kontroler a akce a ID něčeho, a všechny ostatní prostě jen načíst (ať už si je pojmenujete nebo ne) a nechat na kontroleru, ať si to nějak přebere.
han5vk
Profil
Rozumiem. Ono, pochybujem že niekedy tam tých parametrov bude toľko, išlo mi len o ten princíp ako to urobiť. Na určenie controllera a metódy budú samozrejme stačiť aj dva , či menej. Išlo mi napríklad o situáciu, kde chcem zobraziť nejaké záznamy o používateľovi a zoradiť ich podľa niečoho, kde by mi vznikla nejaká takáto URL: foo.bar/logs/user/fantomas/date , kde na určenie controlleru a metody stačia prvé dva, pričom ostatné by si už spracoval samotný controller, teda tá akcia, ktorá by zistila či taký používateľ existuje, vytiahla jeho záznamy a zoradila podľa dátumu.

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: