Diskuze: MVC/MVP - závislost jednoho modelu na jiných
V předchozím kvízu, Online test znalostí PHP, jsme si ověřili nabyté zkušenosti z kurzu.

Tvůrce

Zobrazeno 9 zpráv z 9.
//= Settings::TRACKING_CODE_B ?> //= Settings::TRACKING_CODE ?>
V předchozím kvízu, Online test znalostí PHP, jsme si ověřili nabyté zkušenosti z kurzu.
Ještě jsem zapomněl přiložit odkaz na fórum Nette:
Nikdo neví, nebo jsou všichni líní to číst a přemýšlet?
Já jsem rád, že si naťukám v PHP kontaktní formulář, tohle je na mě
velká liga moc
Priznam sa ze som si to precital a otazka nie je jednoznacna. Takze ani odpoved nebude jednoznacna. Nette nepoznam, predpokladam ale ze je to nejaky novsi framework pouzivajuci composer atd.
SRP zachovaj v kazdom pripade Moje modely su ciste, bez hluposti. Kazda classa ma na validaciu vlozenia dat svoju classu a presenter je dalsia classa. Tymto sposobom mozem hocikedy pouzit ten isty model v kazdej poziadavke.
Service classa je helper classa ktora toto vsetko spaja a je v podstate instanciovana v controlleri. Service classa kontroluje co sa bude robit s ktorym modelom a kedy. Vidim ze ty tvoje service classy volas factory, co nie je uplne spravne. Service classa nemusi byt factory. Neviem ci chapem spravne tvoju MVC strukturu. Vies sem pridat nejaky nakres? Ja som sem prilozil taky zjednoduseny nakres, aby si videl co je moja service classa.
Controller posuva viewu priperavene objekty a view si ich zobrazuje ako treba alebo si zavola presenter konkretneho modelu.
Samozrejme som este vynechal kopu veci ako su eventy, queues ... Takze neviem ci som ti odpovedal, ci si hladal radu ohladom MVC, nette frameworku alebo tvojho konkretneho problemu alebo si len chcel podebatit o tvojich nazoroch na dependency hell.
Díky za odpověď.
V Nette je Presenter něco jako prostředník mezi view (šablona) a modelem.
Zpracovává požadavky od uživatele, volá příslušné metody modelových
tříd a předává data šablonám.
Životní cyklus presenteru pak vypadá takto:
http://files.nette.org/…fecycle2.gif
Startup slouží pro inicializaci vlastností v daném presenteru.
Action se většinou stará o případné změny ještě před vykreslením
šablony (změna layoutu, nastavení defaultních hodnot formuláře atp.).
Signál je pro požadavky, které mají např. upravit záznam v databázi.
Before render a render se starají o naplnění proměnných pro danou
šablonu.
Presenter má také přístup k DI Containeru, který má v sobě uložené
servisní třídy (vždy vrací jen jednu instanci), továrny (pokaždé
vytvoří novou instanci) a konfigurační nastavení dle .neon
(konfiguračního) souboru.
Model je pak čistě na vývojáři, jak si ho vytvoří. Není tam pro něj
žádný interface.
Obvykle model stavíš tak, že má více tříd (v tomto případě např.
Player, Item, Message). Otázka je, jak udělat, aby se na jedné operaci mohlo
podílet více modelových tříd.
Pro příklad - hráč koupí od někoho předmět. Oběma hráčům pak přijde
zpráva o provedeném obchodu. Znamená to, že se na této jedné operaci
podílí tři modelové třídy a dohromady 5 objektů:
Podle mě je nesmysl, aby to celé mohl udělat objekt třídy Player
$player->buyItem($itemId);
protože objekt hráče by neměl umět posílat zprávy a modifikovat
předmět (pak by to bylo porušení SRP), ale v tomto případě jen
přičíst/odečíst peníze.
Logická možnost by byla udělat pro danou operaci speciální třídu, třeba
ItemSale, které bys předal všechny potřebné objekty (tříd Player, Item a
Message).
Metoda by pak použila všechny objekty a provedla celý proces koupi předmětu
(přičtení a odečtení peněz, změnu vlastníka předmětu a poslání dvou
zpráv).
Zde ale nastává problém - v tomto případě musím už předem vědět,
kdo je vlastníkem předmětu, a vytvořit příslušný objekt (který předám
objektu třídy ItemSale).
Co když ale budu potřebovat ten objekt vytvořit až uvnitř metody třídy
ItemSale? Tam není možnost, jak ten objekt vytvořit, protože nemá přístup
k DI Containeru.
Asi ti rozumiem:
$Hrac->kupPredmet($predmetId);
Hrac je model v DB a ma sa starat o data z DB iba ohladne Hraca a nie aj o predmetoch, nedajboze posielat emaily predavajucemu/kupujucemu. S tymto s tebou suhlasim.
Trieda ItemSale sa mi nepaci. Nerobim classy ktore maju len jedno pouzite. Na jedno pouzitie su metody, z toho mi vyplyva ze itemSale bude metoda v nejakej classe.
Presenter ma pristup k service kontaineru, takze tvoja metoda ItemSale bude tu. Ak chces predavvat predmet, musis uz poznat objekty kupujuceho, predavajuceho a predmet. Metoda sa bude volat napr:
public function ItemSale( Player $buyer, Player $seller, Item $item)
{
...
return $success;
}
Metoda vracia boolean, takze vies ci posielat emaily, alebo posielanie emailov zavolas vo vnutri itemSale.
Tvoj presenter je asi Controller v mojom nakrese. Vsetky tieto metody by mali byt v pomocnej triede, takze presenter by mal byt cisty a lahko citatelny.
Objekty si podavame, ked volame metodu, tak ako som uviedol v itemSale a neinicializujeme ich vo vnutri! Ked budes robit UnitTesty, tak zistis ze metodu vies lepsie testnut ak si objekty 'mock'-nes a tiez nebudu tvoje testy pomale kvoli ustavicnemu spojeniu s DB. Je tam plno vyhod ale o tom inokedy.
Teraz ked pozeram lepsie ten tvoj pastebin tak:
public function handleBuyItem($id)
{
$item = $this->itemFactory->create($id);
$ownerId = $item->getData()->ownerId;
// relace nyní obsahuje objekty kupujícího hráče, vlastníka předmětu a samotný předmět
$relation = $this->createRelation("playerItem");
$relation->player = $this->player;
$relation->item = $item;
$relation->owner = $this->playerFactory->create($ownerId);
try {
$relation->buyItem();
} catch (Exception $e) {
$this->flashMessage($e->getMessage()); // zpráva, která se poté objeví na stránce
$this->redirect("default");
}
}
Ja tam nevidim ziadne
$player->buyItem($itemId);
Odkial mas ten kod co si dal sem do otazky? To je tvoj refactoring, kde si
chcel celu tu funkciu presunut do presentera? Tak to tak urob, ale bez tych
factory a na buyItem si sprav tiez triedu v presenteri. Aha, to bola tvoja
original otazka?
Vážně moc děkuju za příspěvek.
Ta metodu
$player->buyItem($itemId);
jsem si vymyslel, abych ukázal, jaké řešení by se mi nelíbilo (tj. aby objekt $player s metodou buyItem() i poslal zprávu a upravoval předmět), v kódu ji nemám.
Tvá zpráva mi opravdu pomohla, díky!
Zobrazeno 9 zpráv z 9.