Zobrazení novinek

Rudolf Svátek 2016-07-28 12:55

Aplikace ke stažení po dnešní lekci: kapitola20.zip.

Novinky mají smysl na webech, kde se často něco děje. Majitelé stránek ale často propadají obsedantní potřebě nějaké novinky na stránkách mít, i když jde o řemeslníka, který má na webu 5 stránek a od doby jejich vzniku nemá potřebu cokoli na webu měnit, či zveřejňovat. Poslední novinkou na mnoha webech je tedy 3 roky starý výkřik - "Máme nový web".

Nicméně náš redakční systém už má administraci novinek, no tak je uživatelům necháme zobrazit. Opět to bude pomocí komponenty. Také budeme chtít zobrazit detail novinky, případně vypsat úplně všechny novinky a ne třeba jen posledních 5. Třeba jich bude fakt hodně, tak je ještě budeme stránkovat a listovat mezi nimi.

Začneme tedy presenterem pro zobrazení novinek.

Presenter novinek

<?php

namespace App\FrontModule\Presenters;

use App\Model\NewsEntity;
use App\Model\NewsRepository;

class NewsPresenter extends BasePresenter
{

	/** @var NewsRepository @inject */
	public $newsRepository;

	public function startup() {
		parent::startup();
	}

	/**
	 *
	 */
	public function actionDefault() {
		$news = $this->newsRepository->getAll()->where(['active' => 1])->orderBy(['dateAdd' => 'DESC']);

		$visualPaginator = $this['visualPaginator'];
		$paginator = $visualPaginator->getPaginator();
		$paginator->itemsPerPage = $this->settings['newsPerPage'];
		$paginator->itemCount = $news->count();
		$news->limit($paginator->itemsPerPage);
		$news->offset($paginator->offset);

		$this->getTemplate()->news = $news->fetchAll();
		$this->getTemplate()->title = "Novinky - " . $this->settings['siteName'];
		$this->getTemplate()->description = "Novinky - " . $this->settings['siteName'];
		$this->getTemplate()->keywords = "Novinky, " . $this->settings['siteName'];
	}

	/**
	 * @param $id
	 */
	public function actionView($id) {
		/** @var NewsEntity $new */
		$new = $this->newsRepository->get($id);
		$this->getTemplate()->new = $new;
		$this->getTemplate()->title = $new->title();
		$this->getTemplate()->description = $new->title();
		$this->getTemplate()->keywords = "";
	}

}

Je to vlastně pořád dokola stejné - předat závislosti a přidat metody pro různé akce a zobrazení. Tady chceme mít pouze 2 akce: pro zobrazení výpisu všech novinek a pro zobrazení detailu jedné novinky.

V tom výpisu si připavuji stránkování pomocí VisualPaginatoru. No ale odkud ho ten presenter má znát? Nabízí se zase BasePresenter. Předpokládám totiž, že budu chtít stránkovat i jiné věci než novinky a pak se to bude hodit. Čili v BasePresenteru doplníme metodu:

	/**
	 * Create items paginator
	 * @return VisualPaginator\Control
	 */
	protected function createComponentVisualPaginator() {
		$control = new VisualPaginator\Control;
		$control->setTemplateFile('bootstrap.latte');
		$control->enableAjax();
		$that = $this;
		$control->onShowPage[] = (function ($component, $page) use ($that) {
			if ($that->isAjax())
				$that->redrawControl();
		});
		return $control;
	}

Nezapomenu samozřejmě na

use IPub\VisualPaginator\Components as VisualPaginator;

Pak samozřejmě šablony. Jednu na zobrazení výpisu - default.latte:

{block content}
<h1>Novinky</h1>
<div id="content">
	{snippet news}
	<div class="news" n:foreach="$news as $new">
		<h2><a n:href="News:view $new->id">{$new->title}</a></h2>
		<p>{$new->text|noescape|striptags}</p>
		<p class="post-meta"><span class="glyphicon glyphicon-time"></span> {$new->dateAdd|date:"Y-m-d H:i:s"}</p>
	</div>
	{control visualPaginator}
	{/snippet}
</div>

Druhou na zobrazení detailu - view.latte:

{block content}
<div id="content">
	<h1>{$new->title()}</h1>
	<p>{$new->text()|noescape|striptags}</p>
</div>

Upravit to podle sebe určitě zvládneš. Třeba přidat v detailu novinky odkaz na výpis všech novinek.

Komponenta novinek

<?php

namespace App\FrontModule\Controls;

use Nette\Application\UI;
use App\Model\NewsRepository;

class NewsControl extends UI\Control
{

	/** @var NewsRepository */
	private $newsRepository;

	/**
	 * @param NewsRepository $newsRepository
	 */
	public function __construct(NewsRepository $newsRepository) {
		parent::__construct();
		$this->newsRepository = $newsRepository;
	}

	/**
	 * @param null $params
	 */
	public function render() {
		$news = $this->newsRepository->getAllWhere(['active' => 1])
				->orderBy('dateAdd DESC')
				->limit(5);
		$this->getTemplate()->news = $news;
		$this->getTemplate()->setFile(__DIR__ . '/NewsControl.latte');
		$this->getTemplate()->render();
	}

}

Začátek je tradiční - předání závislosti na repositáři. Pak v metodě render() získáme data, čili 5 posledních aktivních novinek. Zvolíme název šablony a vykreslíme. Fakt nic složitého. Jen snad námět na vylepšení - pro výběr novinek volám z repositáře metodu getAllWhere a výsledek pak řadím a limituji na 5 záznamů. To by chtělo přepsat. V repositáři by měla vzniknout metoda, která vrací potřebný počet aktivních novinek, seřazených sestupně. Ta by je získala zase z mapperu, ve kterém by opět vznikla metoda, která by ta data vytáhla z databáze.

Jestli se ptáš proč vytvářet v repositáři další metodu, která stejně jen bude volat v mapperu metodu, co teprve získá data z databáze, tak vysvětlím: jediný, kdo by měl pracovat s úložištěm dat, je mapper. Ten jediný ví, co vlastně používá za typ úložiště. Repositář by to vědět neměl. Ten jen dostane nějaká data a může si s nimi dělat co uzná za vhodné. V presenteru už vůbec nemůžeme spoléhat na to, že jsou data získána z nějakého konkrétního úložiště, nebo nějakým konkrétním způsobem.

Takže když tady v komponentě volám ->orderBy a ->limit, což je konstrukce z dibi, spoléhám se na to, že to neskončí chybou a že to vůbec jde. Kdyby ale funce getAllWhere dostala z mapperu výsledek třeba ve formě pole, tak tady by to skončilo chybou.

Zkus to opravit a ty metody vymyslet :-)

Šablona novinek

Také šablona komponenty novinek je primitivní:

<div class="news row">
	<h3>Novinky</h3>
	<p n:foreach="$news as $new">
		<a href="{plink News:view $new->id}">{$new->title}</a>
	</p>
</div>

Čistě jen napíšu nadpis a pak vypíšu novinky v nějakém cyklu. Klidně si to uprav podle sebe - změň h3 na něco jiného, použij nečíslovaný seznam místo odstavců, doplň k novince datum přidání apod.

Úprava presenteru

Uvažuji tak, že budu chtít novinky vypisovat všude - na úvodní stránce, když zobrazím textovou stránku, pod výsledky vyhledávání atd. Takže komponentu vytvořím v BasePresenteru:

	/**
	 * @return NewsControl
	 */
	public function createComponentNewsControl() {
		$control = new \App\FrontModule\Controls\NewsControl($this->newsRepository);
		return $control;
	}

Opět jedna změna oproti mým zvyklostem je vidět: volám vytvoření instance NewsControl pomocí celé cestu namespace - new \App\FrontModule\Controls\NewsControl(). To funguje. Nicméně já raději uvádím cesty v klauzuli use. Ale zase to nechám na tobě. Já si třeba pro sebe to volání upravím na new NewsControl(), protože si přidám use App\FrontModule\Controls\NewsControl;

Přijde mi to přehlednější. A pokud potřebuji volat tu třídu několikrát, zmenšuje se zdrojový kód.

Samozřejmě musíme BasePresenteru dodat i závislosti, ale já už s tím počítal, takže potřebné řádky:

use App\Model\NewsRepository;

a v těle třídy:

	/** @var NewsRepository @inject */
	public $newsRepository;

už mám. Měl bys je tam mít taky. Čili už jen zbývá někde ty novinky vypsat. Můžeme upravit hlavní šablonu, nebo jednotlivé šablony podle toho, kde ty novinky chceme vypsat. Takže najdi vhodné místo/místa v nějaké šabloně a vlož:

{control newsControl}

A tím je to dané - novinky se zobrazí. Čili dnes už to stačí. Aplikace ke stažení po dnešní lekci: kapitola20.zip.

Redakční systém RS::RS Předchozí kapitola

Komentáře k článkům

Redakční systém RS::RS Celý seriál

Vývoj redakčního systému v PHP

Redakční systém RS::RS Následující kapitola

Vyhledávání na webu

Komentáře (0)

Přidej svůj komentář

O mně

Jmenuji se Rudolf Svátek. Jsem lektor výpočetní techniky a PHP programátor. Stavím firemní stránky a eshopy. Aby se mi to dělalo pohodlně, vytvořil jsem redakční systém RS::RS, který ti tu nabízím k použití.

Rychlý kontakt na mně

  • Rudolf Svátek
  • Telefon:
    +420 777 828 353
  • Email:
  • Adresa:
    Josefa Hory 1097/5
    736 01 Havířov
    ČR



Tyto stránky používají Cookies. Používáním stránek s tím souhlasíte Další informace