Routování odkazů Controlu na sebe sama

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

Zdravím Nette komunitu, můj dotaz směřuje na routy v rámci komponent…

Vytvořil jsem si komponentu BlogWidget, která se umí

  • zobrazovat seznam článků
  • zobrazovat detail článku
  • zobrazit formulář pro přidání nového článku

Chtěl bych se zeptat:

  • dá se nějak nastavit routy v rámci komponent, aby url aplikace nebylo /?blogWidget-id=3&do=blogWidget-Detail ale např. /blog/titulekclanku-idclanku ?
  • co si myslíte o tomto řešení, kdy se nepoužívají Presentery, ale je vše v komponentě ?

Kód vypadá následovně:

BlogWidget.php

class BlogWidget extends Control {
        public $action = 'default';

        function handleAdd() {
                $this->action = 'admin';
        }

        function handleList() {
                $this->action = 'default';
        }

        function handleDetail($id) {
                $this->action = 'detail';
                $this->template->detail = BlogWidgetModel::getArticleById($id);
        }

        public function createComponentBlogAdminForm() {
                $form = new Form();
                $form -> addText('title','Titulek článku');
                $form -> addTextarea('text','Text článku');
                $form -> addSubmit('send','Vytvoř');
                $form -> onSuccess[] = callback($this , 'addItem');
                return $form;
        }

        public function addItem($form) {
                $vals = (array)$form->getValues();
                BlogWidgetModel::insert($vals);
                $this->flashMessage('Aktualita přidána');
                $this->redirect('List');
        }

        function render() {
                $this->template->setFile(dirname(__FILE__).'/BlogWidget.latte');
                $this->template->action = $this->action;
                $this->template->articles = BlogWidgetModel::getNews();
                $this->template->render();
        }

}

BlogWidget.latte

{if $action=='default'}
        {foreach $articles as $a}
                <h2><a n:href="Detail,id=>$a->id">{$a->title}</a></h2>
                <p>{$a->text}</p>
                {sep}<hr>{/sep}
        {/foreach}
        <a n:href="Add">Přidej novou položku</a>
{/if}

{if $action=='admin'}
        {widget blogAdminForm}
{/if}

{if $action=='detail'}
       <h2>{$detail->title}</a></h2>
       <p>{$detail->text}</p>
{/if}

Díky za každou reakci..

Filip Procházka
Moderator | 4668
+
0
-

Mám velkou radost, že na to chceš dělat komponentu, protože to považuju za správný směr :)

Takže několik doporučení:

  1. mít jednu šablonu pro komponentu a v ní ify je škaredé. Koukni na LookoutControl, když ho podědíš můžeš psát pak „pohledy“ podobně jako v presenteru a ke každému máš šablonu.
  2. asi bych na tři účely nepsal jednu komponentu, ale tři komponenty
  3. asi bych komponenty více řídil presenterem, to znamená každé komponentě buď předávat konstruktorem ID článku a model, nebo rovnou článek, získaný v akci
protected function createComponentArticleDetail()
{
	$id = $this->getParam('id', NULL);
	if ($id === NULL) {
		throw new Nette\Application\BadRequestException('Missing article ID');
	}

	return new ArticleDetail($this->context->articleModel, $id);
}

A nebo takto, což mě zrovna napadlo a dává to docela smysl :)

// presenter

/** @persistent */
public $id; // routa sem dosadí IDčko článku

protected function createComponentArticleDetail()
{
	return new ArticleDetail($this->context->articleModel);
}
{control articleDetail $presenter->id}

Komponenta by pak v render přijímala toto $id, vytáhla si článek a vykreslila. Router by měl zařídit, že odkaz na neexistující článek se zahodí dříve, než se dostane požadavek k presenteru.

eudard
Člen | 15
+
0
-

HosipLan napsal(a):

  1. mít jednu šablonu pro komponentu a v ní ify je škaredé. Koukni na LookoutControl, když ho podědíš můžeš psát pak „pohledy“ podobně jako v presenteru a ke každému máš šablonu.

LookoutControl je naprosto geniální!! Připadalo mě, že když používám pro realizaci komponenty, tak se ochuzuju o vymoženosti Presenteru. LookoutControl tohle alespoň z části řeší – díky za tip!

  1. asi bych na tři účely nepsal jednu komponentu, ale tři komponenty

Předpokládám že máš namysli rozdělit komponentu na tři asi nejak takto:

  • blogWidgetDetail.php + šablona
  • blogWidgetList.php + šablona
  • blogWidgetAdmin.php + šablona

s tím, že v presenteru si pak určím co chci zobrazit.. opět super nakopnutí!

Router by měl zařídit, že odkaz na neexistující článek se zahodí dříve, než se dostane požadavek k presenteru.

To řízení presenterem navrhuješ právě kvůli routeru ? O ten mi totiž právě jde, zatím se v tom tak nějak plácám a nemůžu pořádně navrhnout správně routy.

Teď řeším router pro adresu http://localhost/?blogWidget-id=1&do=blogWidget-Detail
aby odkazy vypadaly takto http://localhost/article/id

Zatím jsem přišel na to, že řešení bude pravděpodobně něco jako:

$router[] = new Route("article/<blogWidget-id>/<do>", array(
        'presenter' => 'Homepage',
        'action' => 'default',
        'blogWidget-id'=>NULL,
        'do'=>NULL
));

Ale není to optimální, routy mě dělají zatím problémy. Musím to ještě pořádně nastudovat a otestovat.

Filip Procházka
Moderator | 4668
+
0
-

Mohlo by tě zajímat: https://forum.nette.org/…dnot-pri-mvc

$articleModel = $container->articleModel;

$router[] = new Route('blog/<article>', array(
		'presenter' => 'Article',
		'action' => 'default',
		'articles' = array(
			Route::FILTER_IN => function ($article) use ($articleModel) {
				// vubec nepotřebuješ čísla a pokud budou mít dva články stejný název,
				// ke druhému přidáš na konec dvojku

				return $articleModel->findIdByName($article);
				// pokud model nic nenajde, měl by vrátit NULL
			},
			Route::FILTER_OUT
		)
	));
$router[] = new Route('<presenter>[/<id>]/', array(
		'presenter' => 'Homepage',
		'action' => 'default'
	))

Potom budeš mít presentery ArticlePresenter, kde budeš vypisovat článek, ArticlesPresenter kde bude jejich seznam a můžeš mít i ArticleEditPresenter, který bude vyžadovat přihlášeného uživatele.