jednoduché fórum a zachování mvc

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

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
+
0
-

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

Arynev
Člen | 33
+
0
-

Ano, tohle je mi jasné. Čili si to mám tedy celé vygenerovat jako seznam kategorií už v modelu, a pod nimi topiky? Pak je procházet pomocí foreach?

Asi takhle?
array(
category1,
category2 ⇒ array(topic1, topic2),
category3
)

Šaman
Člen | 2666
+
0
-

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
+
0
-

V takovém případě „getAllCategories()“ nesmí vracet dibidatasource ?

Šaman
Člen | 2666
+
0
-

Proč ne? Při následném iterování to fetchne a vrátí už objekt Category

Arynev
Člen | 33
+
0
-

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
+
0
-

$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)

Arynev
Člen | 33
+
0
-

Jen tak pro zajímavost: jak to udělat čistěji objektově?

22
Člen | 1478
+
0
-

není to ani chvíle, kdy mě Hosiplan okříknul za pominutí Nette školky a aaron za prasárnu ale co je tohle? volat ze sablony model je prasarna na N2. Just my 2 cents.

mkoubik
Člen | 728
+
0
-

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
+
0
-

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é.

Arynev
Člen | 33
+
0
-

Díky za rady