jednoduché fórum a zachování mvc
- Arynev
- Člen | 33
Ahoj, chci si naprogramovat jednoduché fórum a neni mi úplně jasné v jaké podobě mám přenést data z presenteru do templaty.
Tabulky:
- topic int(11) Auto Increment
- topic_title varchar(250)
- parent int(11) NULL
- category tinyint(4) // určuje jestli je pouze kategorie
- post int(11) Auto Increment
- content text
- topic int(11)
- views int(11)
- author int(11)
- datetime datetime
Na úvodní stránce fóra si vyberu kategorie, ty projedu přes foreach a vyberu k nim topiky.
Napadlo mě pouze přidat to vše v jednom poli, ale obávám se že rychlost by nebyla nic moc.
- Šaman
- Člen | 2666
Do šablony předáváš normálně celé objekty. A generovat je můžeš i dynamicky v šabloně.
<?php
//presenter
$categories = $model->getAllCategories();
$this->template->categories = $categories;
//template (předpokládám že kategorie má metodu getTopics() a dědí od Object)
<ul n:foreach="$categories as $category">{$category->title}
<li n:foreach="$category->topics as $topic">{$topic->title}</li>
</ul>
?>
P.S. psáno jen jako nástřel z hlavy
- Šaman
- Člen | 2666
Pokud s tím seznamem nepotřebuješ pracovat v presenteru, tak já bych je generoval až v šabloně. (viz můj příklad, kde se getTopics() volal až v tom <li>)
Je to ale už na filosofické hranici co je čisté MVP©. View si volá model. Ale proč ne? Presenter ti pouze zařídí že se zobrazí správné View a Model sám o sobě by měl být schopný bezpečně obsloužit i požadavek z View (za předpokladu, že si kontrolu přístupu a kontrolu konzistence hlídá už model sám.)
No, snad je to trochu srozumitelné – jak to tak po sobě čtu, zasloužilo by si to rozepsat na delší článek. To teď ale nestíhám.
Editoval Šaman (30. 3. 2011 20:52)
- Arynev
- Člen | 33
Model
<?php
class ForumModel extends BaseModel
{
public function getLastPosts(){
$this->Posts()->fetchAll();
}
public function getTopicPosts($topic){
$posts = $this->Posts()->where('topic = %i', $topic)->fetchAll();
}
public function getCategories(){
return $this->Topics()->where('category = 1')->fetchAll();
}
public function getTopics($parent = NULL){
if($parent == NULL){
return $this->Topics()->fetchAll();
}else{
return $this->Topics()->where('parent = %i', $parent)->fetchAll();
}
}
private function Topics(){
return dibi::dataSource('SELECT * FROM [forum_topics]');
}
private function Posts(){
return dibi::dataSource('SELECT * FROM [forum_posts], [users] WHERE forum_posts.author = users.id ORDER BY forum_posts.datetime');
}
}
Presenter
$model = new ForumModel;
$categories = $model->getCategories();
$this->template->categories = $categories;
template
{block content}
<ul n:foreach="$categories as $category">{$category->topic_title}
<li n:foreach="$category->topics as $topic">{$topic->topic_title}</li>
</ul>
{/block}
Jestli to chápu dobře, tak mi to nechce vrátit objekt, ale já jej tam nikde nevkládal Chyba: „Undefined property: DibiRow::$topics“
- Šaman
- Člen | 2666
$category->topics
neexistuje. Buď musíš dědit od
Nette\Object
a pak se tak dá zkrátit volání metody
$category->getTopics()
, nebo to budeš muset volat polopaticky.
Vypadá to, že tvůj BaseModel
od Nette\Object
nedědí (nebo ano a chyba je jinde?)
Sorry, jsem si pořádně neprohlídnul zdrojáky. Vždyť ty nemáš nikde
definovanou třídu category
. Tak nemůžeš volat ani její metodu
getTopisc
když neexistuje.
Můžeš do šablony předat $model
a pak v šabloně:
<?php
{block content}
<ul n:foreach="$model->getCategories() as $category">{$category->topic_title}
<li n:foreach="$model->getTopics($category) as $topic">{$topic->topic_title}</li>
</ul>
{/block}
?>
Ten tvůj návrh není čistě objektový, takže nemůžeš volat objektově $category->getTopics(), ale musíš si vytvořit metodu $model->getTopics($category) která ti vrátí topiky v dané kategorii.
Editoval Šaman (31. 3. 2011 22:35)
- mkoubik
- Člen | 728
22 napsal(a):
volat ze sablony model je prasarna na N2.
Čistě historicky je tohle právě původní čisté smalltalkovské MVC z 80. let. Viz třeba http://pl.csie.ntut.edu.tw/…C-public.pdf. Pro účely stateless webového prostředí si to vývojáři přiohli tak, že controller do view předává už jenom data. Pro účely generování HTML to stačí, view není klasický GUI prvek takže s objektem modelu nepotřebuje nijak interagovat.
Předávat ale do view přímo objekt modelu není nic proti ničemu, třeba u nějakého datasource se to hodí. Spousta lidí to považuje za prasárnu, ale z pohledu původního MVC jsou „prasárna“ dnešní webové frameworky.
- Šaman
- Člen | 2666
Arynev napsal(a):
Jen tak pro zajímavost: jak to udělat čistěji objektově?
<?php
class Post extends Object
{
public function getTitle()
{ // vrati titulek
// Pokud dedis od Nette\Object, tak zvenku muses volat $post->title
// a ve skutecnosti se tim zavola tato metoda $post->getTitle()
}
...
}
class Topic extends Object
{
public function getPosts()
{ // vrati vsechny posty v tomto topicu
}
}
class Category extends Object
{
public function getTopics()
{ // vrati topicy v teto kategorii
}
public function getCategories
{ // vrati vnorene kategorie
}
}
?>
Je to jenom nástřel, jde o to, že každá entita (Post, Topic..) je
v samostatné třídě a tedy k ní můžeš přistupovat objektově
($category->topics
zavolá
$category->getTopics()
a to vrátí pole objektů (nebo
datasource) Topic
)
P.S. Tohle se už ale týká spíše výuky OOP, než samotného Nette. Takže k tomuto tématu existují kurzy, seriály, články. I když je pravda, že tam tě často seznámí jen se syntaxí a praktické dovednosti musíš nabrat praxí. Mimochodem příklad dobrého OOP návrhu je třeba Nette samotné.