Modelové třídy – perzistentní parametr

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
horakmar
Člen | 16
+
0
-

Ahoj. Zatím stále dost plavu v pochopení (jinak skvělého) Nette – především v tom co všechno si dělá „samo“ a jak. Prosím o jednu radu:

V aplikaci pro správu závodů mám modelovou třídu:

class RaceManager extends Nette\Object {

	/** @var Nette\Database\Context */
	private $database;

	public function __construct(Nette\Database\Context $database) {
		$this->database = $database;
	}

	...

	public function getCourse($raceid, $courseid) {
		$course_table = $raceid . "__course";
		$row = $this->database->table($course_table)->get($courseid);
		return $row->toArray();
	}

}

V aplikaci si uživatel na začátku jednou vybere závod ($raceid) a s ním pak pracuje dál v mnoha dalších presenterech a view.
Presentery dědí z jednoho předka, kde je $raceid perzistentní:

abstract class BaseRacePresenter extends BasePresenter {

   /** @persistent */
    public $raceid;

	...
}

Co bych chtěl, tak dostat $raceid do modelové třídy jako property, abych ho nemusel předávat jako parametr u každé metody.:

class RaceManager extends Nette\Object {

	/** @var Nette\Database\Context */
	private $database;

	/** @var raceid */
	private $raceid;

	...

	public function getCourse($courseid) {
		$course_table = $this->raceid . "__course";
		$row = $this->database->table($course_table)->get($courseid);
		return $row->toArray();
	}

}

Otázkou je, jak ho do modelu z presenteru dostanu?
Je možné dostat ho tam nějak automaticky přes kontruktor?
Kdy se vlastně volá kontruktor modelové třídy a jak se do něj dostávají parametry?
Nebo přes setter – něco jako:

	public function setRaceID($raceid) {
		$this->raceid = $raceid;
	}

Tady bych ale taky potřeboval, aby se volal „nějak“ automaticky, nebo při vytvoření presenteru. Jediné co umím, tak volat ho ručně před voláním metody pro výběr dat a to jaksi ztrácí smysl – to už ho můžu mít rovnou jako druhý parametr výběrové metody:

	...
	$this->manager->setRaceID($this->raceid);
	$this->template->course = $this->manager->getCourse($courseid);
	...

Díky za jakoukoli radu (klidně i že jsem naprosto mimo)
Kdyby byl někde odkaz na příklady nějakých složitějších modelů než databáze CD či blogu, tak bych za ně byl také moc rád.
Nette je super, ale pro začátečníky (navíc začínající i s OOP) má hodně vysoký vstupní práh.

Krásný Nový rok přeje
Martin

F.Vesely
Člen | 369
+
+3
-

Mne se myslenka mit $raceId jako property RaceManageru nelibi. Co kdyz budes chtit nekde vypsat podle vice $raceId?

Nevim, co presne programujes, ale moc se mi nepozdava mit $raceId v nazvu tabulky, jaky to ma duvod? Nebylo by lepsi mit tabulky race a course? Kazdy course by mel FK na race a pak bys mohl pres related() v Nette\Database jednoduse najit vsechny kurzy k zavodu.

David Matějka
Moderator | 6445
+
0
-

jeste doplnim:

Kdy se vlastně volá kontruktor modelové třídy a jak se do něj dostávají parametry?

sluzby se vytvareji v okamziku, kdy jsou potreba – tedy napriklad kdyz se vytvari presenter se zavislostma, tak se vytvoreji vsechny sluzby

Je možné dostat ho tam nějak automaticky přes kontruktor?

teoreticky bys mohl vyzadat Application jako zavislost, ale to nedoporucuji. modelova vrstva by mela byt nezavisla na presenterech apod.

horakmar
Člen | 16
+
0
-

Měla by to být aplikace pro správu orientačních závodů. Raceid v názvu tabulky jsem zvolil proto, aby data jednotlivých závodů byla oddělená a celá sada tabulek $raceid__<neco> se dala snadno přenést jinam, nebo zkopírovat. Také se tím zbavím sloupce raceid v každé tabulce (kdybych měl všechny závody v jedné sadě).
Uživatel si při vstupu do aplikace zvolí závod z výpisu (nebo založí nový – což v DB vygeneruje novou sadu tabulek). Tím si vybere $raceid a pak už pracuje ve všech presenterech a view jenom s ním. V presenteru ho už umím držet jako perzistentní, ale hledám způsob, jak ho dostat do modelu aniž bych ho musel v každé metodě přenášet jako parametr.
Nejsem si ale jistý zda to vůbec jde?

Jinak course není kurz, ale trať. :-) Tabulky mají složitější strukturu – závod obsahuje kategorie, tratě, závodníky, výsledky, …

David Matějka
Moderator | 6445
+
0
-

Nekomplikuj si zivot a nevytvarej za behu tabulky, to je cesta do pekel, co kdyz budes chtit nekde vypsat trate z vice zavodu? to budes muset prochazet vsechny tabulky. co kdyz budes chtit pridat trati nejakou vlastnost (sloupecek)? vytvor si pro trate jednu tabulku a ukladej tam id zavodu.

a tim se castecne vyresi i tvuj druhy problem, kdyz to budes mit v jedne tabulce, tak nebudes muset napriklad pri vyberu trati dle id znat (a tudiz tam nejak dostavat) to id zavodu

horakmar
Člen | 16
+
0
-

Už jsem to dlouho promýšlel.
Vypsat něco z více závodů najednou nebude nikdy (nikdy neříkej nikdy :-) potřeba. Kromě jednoduchého výpisu všech závodů kvůli výběru.
Pokud budu potřebovat přidat sloupec, pak ho přidám v tabulkové šabloně ze které se nové tabulky generují. Což samozřejmě ovlivní pouze nové závody. Ale s tím počítám.
Pořád mám pocit, že takto si život spíš zjednoduším. :-)
Stále ale nikdo neodpověděl na to, na co jsem se ptal… :-))

David Matějka
Moderator | 6445
+
+3
-

tim vytvareni tabulek si to neskutecne komplikujes, ver mi.

Což samozřejmě ovlivní pouze nové závody. Ale s tím počítám.

a jak treba budes chtit vyresit pristup k nejakemu novemu sloupecku (at uz v modelove vrstve, presenteru nebo sablone).. kdyz nekde nebude existovat, tak to vyhodi vyjimku…

Pořád mám pocit, že takto si život spíš zjednoduším. :-)

v zadnem pripade :)

udelej si proste dve tabulky, jak uz radil @F.Vesely, v jedne bude seznam zavodu a v druhe seznam trati – a u kazde trati bude id zavodu. pak budes moct pouzivat ruzne ref a related z ndb..

Stále ale nikdo neodpověděl na to, na co jsem se ptal… :-))

jak jsem psal v predchozim prispevku, kdyz si to nebudes komplikovat vytvarenim tabulek, tak ten problem nebudes muset resit. A kde porad bude nutne ten parametr predat, tak ho proste predej jako parametr metody.

F.Vesely
Člen | 369
+
+1
-

Kdo chce kam,… Muzes si ho tam predat pres setter v metode startup().
Ale ty tu prave resis problem, ktery bys resit nemusel, kdybys mel tabulku race a vsude spravne vytvoreny FK. Pak by sis pekne v BasePresenteru vytahl race (tim rovnou otestoval, jestli existuje) a pak jen hazel ->related('course'), ->related('category'), … Nemusel bys psat tucet metod v RaceManageru.

horakmar
Člen | 16
+
0
-

Díky zatím za všechny příspěvky.
Jen pro ilustraci, kolik ve skutečnosti tabulek je a jak by to celé mělo fungovat:
g__race … seznam závodů s jejich parametry (mj. raceid)
<raceid>__category … kategorie
<raceid>__course … tratě
<raceid>__course_cp … seznam kontrol (checkpoints) jednotlivých tratí
<raceid>__entry … přihlášky
<raceid>__read … přečtené výsledky (elektronicky čtené záznamy)
<raceid>__read_punch … seznam kontrol jednotlivých výsledků
<raceid>__results … zpracované výsledky
<raceid>__splits … zpracované mezičasy
<raceid>__best_splits … nejlepší mezičasy (kvůli tisku výsledkových lístečků ihned po přečtení výsledků)

Možná ještě nějaká tabulka přibyde, model stále tvořím „za běhu“. :-)

Závod se skládá z kategorií, každá má přiřazenu trať a každá trať několik kontrol.
Kontroly mají kódy, které se při závodě razí do čipu a ten se v cíli přečte – vyleze seznam kontrol s časy ražení na každé z nich a je třeba ověřit, zda má závodník všechny a ve správném pořadí.
Každá přihláška má kromě osobních údajů kód čipu a přiřazenou kategorii, ale v plánu je udělat autodetekci kategorie podle kódů kontrol ve výsledku – vyzkouší se všechny dostupné tratě dokud jedna z nich „sedne“.
Ihned po přečtení seznamu kontrol je potřeba spočítat mezičasy mezi jednotlivými kontrolami a ztráty na nejlepší mezičasy – proto tabulka best_splits.

Pořád mi vychází, že pokud budu mít jen jednu sadu tabulek, budu muset skoro v každé stejně rozlišit o jaký závod se jedná a mít tak stejně v každé sloupeček raceid.

Ale zpět k otázce:

Muzes si ho tam predat pres setter v metode startup()

Můžeš to prosím trochu vysvětlit, nebo mě odkázat na nějaký příklad? To je asi to co hledám.

F.Vesely
Člen | 369
+
0
-

horakmar napsal(a):
Závod se skládá z kategorií, každá má přiřazenu trať a každá trať několik kontrol.
Kontroly mají kódy, které se při závodě razí do čipu a ten se v cíli přečte – vyleze seznam kontrol s časy ražení na každé z nich a je třeba ověřit, zda má závodník všechny a ve správném pořadí.

Pekne sis tu popsal, jak by mela vypada struktura vsech tabulek.

  1. tabulka race (id, …)
  2. tabulka category (id, race_id, …)
  3. tabulka course (id, category_id, …)
  4. tabulka course_cp (id, course_id, …)

Ja tu vidim jen jeden FK na tabulku race.

horakmar
Člen | 16
+
0
-

Není tomu tak.
Relace course – category je obrácená (několik různých kategorií může mít stejnou trať), ale to je detail. Horší je, že při tvorbě závodu se stavitel třeba rozhodne změnit trať pro kategorii a já mu musím dát na výběr seznam dostupných tratí, stejně tak potřebuju (třeba pro sestavení výsledků) seznam kategorií. Vždy však pro jeden konkrétní závod.
I u všech ostatních tabulek bych musel mít FK na race.
U sady tabulek pro konkrétní závod pořád vidím značnou přidanou hodnotu v tom, že můžu závod snadno přenést jinam, zkopírovat, nebo zazálohovat. Prostě vezmu dump konkrétní sady tabulek, aniž bych musel složitě vyhledávat které záznamy musím exportovat.
Asi jsem ještě nezmínil, že aplikace je psána především pro lokální použití – v lesích a horách kde obvykle běháme často není signál pro spolehlivé připojení k serveru. :-) Možnost použít jí na serveru je ale opět přidaná hodnota – třeba pro online výsledky.

Jinak jsem si vyhledal v dokumentaci tu metodu startup() a už mi to funguje:

public function startup() {
	parent::startup();
	$this->manager->setRaceID($this->raceid);
}

To je přesně to co jsem potřeboval a máte mé vřelé díky!

Martin