Získání proměnné z komponenty do šablony (@layout.latte)
- sd
- Člen | 87
Ahoj,
mám komponentu vykreslující články. Ten stejný výpis používám
např. i u vyhledávání, výpis u autora atd – proto tedy jako
samostatná komponenta.
V rámci výpisu mám samozřejmě i stránkování – je nějaká cesta jak
dostat aktuální stránku a maximální počet stránek do presenteru ⇒ do
šablony abych mohl si mohl latte blokem vložit do hlavičky <meta
rel=„next“ ..> a <meta rel=„prev“ …>.
Je na takovou situaci nějaké elegantní řešení?
Díky moc!
sd
- Kamil Valenta
- Člen | 820
- na jedné stránce může být více komponent, např. „A“ a „B“
- komponenta „A“ bude v paginatoru na 3. straně
- komponenta „B“ bude v paginatoru na 4. straně
Jaké next a prev bude v meta?
Jinak ano, komponenta může zavolat public metodu presenteru, ale není to úplně šťastné.
- sd
- Člen | 87
Díky moc za reakce.
@kamil_v
Díky, chápu, jen já mám stránkování integrované přímo do té
vypisovací komponenty – prostě vypíše všechny článku vč.
stránkování – takto bych musel rozdělit výpis a stránkování a pro
každou stránku vkládat komponentu s danou stránkou, tak jsi to myslel?
Následně pak v default.latte
si přepsat blok
v @layout.latte
{block meta-link-prev-next}
<link rel="next" href="{plink //this "articlesList-page" => $pag_cur+1}" n:if="...">
<link rel="prev" href="{plink //this "articlesList-page" => $pag_cur-1}" n:if="$pag_cur > 1 ...">
{/block}
@Šaman
Díky moc, tvoje řešení mi asi přijde o něco hezčí.
public function renderDefault() {
$this->template->currentPage = $this['articlesList']->getPage();
}
v ArticlesList mám
/** @var int @persistent */
private $page = 1;
/** @var int */
private $lastPage;
...
private function loadArticles (...): void
{
// načte články, nastaví
$this->page = ..
$this->lastPage = ..
}
public function getPage(): int
{
return $this->page;
}
public function getPageLast(): int
{
return $this->lastPage;
}
/**
* CONTROLS ****************************************************************
*/
protected function createComponentSortByForm(): SortByForm
{
$control = $this->sortByFormFactory->create();
$control->onSort[] = function (string $sortBy) {
$this->redirect('this', ['sortBy' => $sortBy]);
};
return $control;
}
/**
* RENDER ******************************************************************
*/
/**
* Render content
*/
public function render(): void
{
$page = (int)$this->getParameter('page');
if ($page == 0) {
$this->page = 1;
} else {
$this->page = (int)$this->getParameter('page');
}
$this->template->sortBy = $this->getParameter('sortBy');
$this->template->cid = $this->id;
$this->template->page = $this->page;
$this->template->lastPage = $this->lastPage;
$this->loadArticles((int)$this->id, $this->page, $this->sortBy); // Loads articles
$this->template->setFile(__DIR__ . '/templates/content.latte');
$this->template->render();
}
Takto nějak jsi to myslel? Jen jsem narazil na problém, že při volání render metody v presenteru data v komponentě ještě nejsou načtená – vrací mi tedy defaultní hodnoty.
Editoval sd (18. 2. 2020 11:45)
- Kamil Valenta
- Člen | 820
Ne, já to myslel tak, že na stránce může být více různých komponent a každá z nich si bude nárokovat META. A nerozumím tomu, proč by se presenter měl dotazovat komponenty na page, aby věděl, co má poslat do META.
„Šéf se nechodí ptát podřízeného, co má dělat jiný podřízený. Šéf to ví a všem podřízeným to oznámí“.
Takže bych si spíš představoval, že presenter ví z URL, na které page je a jen to setne do komponenty.
- sd
- Člen | 87
Díky @kamil_v za reakci. To chápu. Asi je chyba, že komponentě předávám de facto „Zobraz mi všechny články autora XY“ nebo „Najdi a zobraz všechny články s XY v titulku“ – narážím tedy na problém pokud bych diktoval z presenteru jakou stránku zobrazit, tak nevím, jestli ta stránka ještě vůbec existuje (celkový počet stránek zná jen ta komponenta)
- Kamil Valenta
- Člen | 820
Celkový počet stránek má vědět model. A toho se může zeptat presenter i komponenta :)
- Šaman
- Člen | 2663
Ale proč by to presenter dělal? Zodpovědnost za stránky je věc té komponenty. Presenter by si musel zjistit jak je komponenta nastavená (třeba kolik se zobrazuje článků na stránce), navíc pokud se cokoliv v logice stránkování změní, musel by se změnit taky.
Pod komponentou je samozřejmě model, ale s ním se má bavit komponenta. Presenter má za úkol vytvořit zobrazit tu komponentu. Jestli chce něco z její kompetence, ať se ptá jí.
- Kamil Valenta
- Člen | 820
Presenter má odbavit request. Pokud mu přijde „/articles?page=2“, tak
má vytvořit komponentu a říct ji, ať zobrazí 2. stránku, nastavit META a
plno dalších souvisejících věcí.
Věcí komponenty už může být jak ta data zobrazí.
Pokud to necháš řídit komponentou, tak stále nevím, jak budeš řešit situaci, kdy na jedné URL bude více komponent (což je běžný stav) a každá si bude nárokovat META po svém.
- Šaman
- Člen | 2663
Komponenta si META nebude nárokovat. Ale pokud je stránkovač
součástí komponenty, tak i v requestu bude číslo stránky někde v
article-control-page=2
a Nette (na úrovni presenteru) to zpracuje
a předá hodnotu komponentě. Tedy komponenta číslo stránky bude vědět (a
bude znát i další nastavení, právě ten počet příspěvků na stránku a
už bude mít vazbu na model který zná počet příspěvků apod.)
Presenter by tyhle rutiny duplikoval (navíc by potřeboval ArticleModel jako
závislost pro zjištění počtu článků). Imho – když už na to mám
komponentu, tak ji nechám obalit všechnu práci s články a
stránkováním.
Meta je ale věc celého HTML výstupu, takže to by měl nastavit presenter. On už by měl vědět které komponenty na stránce jsou a ze které (a jestli vůbec) nastavovat META tag. Ale na číslo stránky a informace, jaká je předchozí a následující – na to by se měl zeptat komponenty, ta tomu rozumí.
Editoval Šaman (20. 2. 2020 11:17)
- sd
- Člen | 87
Díky moc oběma za příspěvky. Jakoby řešení od @Šaman mi přijde čistější, ale nepodařilo se mi ho zrealizovat.
Koncepčně mám komponentu ArticlesList, které předám jen podle čeho má
články zobrazit a ona si je vytáhne z modelu, řeší stránkování a
uživatelskou volbu řazení. Jenže se mi nedaří získat poslední stránku
getterem z ArticlesList
/jak navrhoval Šaman/. Aktuální stránka
je v pořádku, ale počet stránek se mi vrací defaultní hodnota (null). Na
tom jsem se zasekl a implementoval zatím řešení od Kamila. Neví někdo co
dělám špatně?
final class ArticlesList extends BaseControl {
...
/** @var int @persistent */
private $page = 1;
/** @var int */
private $lastPage = null;
...
public function getPage(): int
{
return $this->page;
}
public function getPageLast(): int
{
return $this->lastPage; // Když v render metodě šabloně si zavolám $this['articlesList']->getPage(), dostanu vždy null.
}
private function loadArticles(int $id, int $page, string $sort = 'default')
{
$articlesList = // získání z modelu ...
$articlesCount = $articlesList->count();
$this->template->articles = $articlesList->page($page, 24, $this->lastPage);
$this->page = $page;
$this->template->page = $this->page;
$this->template->lastPage = $this->lastPage;
$this->template-> articlesCount = $articlesCount;
}
public function handleLoadMore(int $id, int $page, string $sortBy): void
{
$this->loadArticles($id, $page, $sortBy);
$this->redrawControl('articles-more');
$this->redrawControl('articles-pagination-top');
$this->redrawControl('articles-pagination-bottom');
}
public function render(): void
{
$page = $this->getParameter('page');
$this->page = $page == 0 ? 1 : $page;
$this->template->sortBy = $this->getParameter('sortBy');
$this->template->cid = $this->id;
$this->loadArticles($this->id, $this->page, $this->sortBy); // Načtení článků
$this->template->setFile(__DIR__ . '/templates/content.latte');
$this->template->render();
}
}
EDIT: doplněný kód
Editoval sd (23. 2. 2020 21:03)
- Kamil Valenta
- Člen | 820
Což je v pořádku, alespoň podle ukázky, kterou jsi poslal, lastPage je
null.
Patrně jsi třema tečkama vypustil to nejzajímavější :)
- Kamil Valenta
- Člen | 820
A kdy na to saháš v tom presenteru? IMHO na to saháš v presenteru dřív, než to v renderu kompoenty naplníš. Ale to jen tak odhaduju.
- Šaman
- Člen | 2663
Ta komponenta se nejprve vytvoří, pak připojí k presenteru, ale dokud se
nevykreslí, tak se neprovede metoda render()
. Takže ani
loadArticles()
. To načtení (inicializaci) proveď
v konstruktoru, nebo (pokud bys k tomu chtěl něco z presenteru), tak
v metodě attached()
. Ta se zavolá ve chvíli, kdy se připojí
k presenteru.
P.S. A cokoliv posílat do šablony
($this->template->page = $this->page;
) bys měl dělat
jen v render metodě.
Editoval Šaman (24. 2. 2020 2:17)