Lekce 8 - Jednoduchý redakční systém v Symfony - Administrace
V minulé lekci, Jednoduchý redakční systém v Symfony - Výpis článku, jsme vytvořili základní strukturu pro výpis článků.
Dnes do kontroleru přidáme akce pro vytváření, mazání a editaci článků.
Kontroler
Jelikož modelovou vrstvu v podobě entity a repositáře máme již nachystanou z minula, začneme rovnou od kontroleru.
src/Controller/ArticleController.php
Protože v Symfony můžeme mít více akcí v jednom kontroleru, budeme
pokračovat v rozšiřování naší třídy ArticleController
a
přidáme do ní následující metody dalších akcí:
<?php namespace App\Controller; use App\Entity\Article; use App\Repository\ArticleRepository; use Doctrine\ORM\ORMException; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Entity; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\Routing\Annotation\Route; /** * Kontroler pro práci s články. * @package App\Controller */ class ArticleController extends AbstractController { /** @var ArticleRepository Repositář pro správu článků. */ private $articleRepository; /** * Konstruktor kontroleru pro práci s články. * @param ArticleRepository $articleRepository automaticky injektovaný repositář pro správu článků */ public function __construct(ArticleRepository $articleRepository) { $this->articleRepository = $articleRepository; } /** * Načte a předá seznam všech článků do šablony. * @return Response HTTP odpověď * @Route("/seznam-clanku", name="article_list") */ public function list(): Response { return $this->render('article/list.html.twig', ['articles' => $this->articleRepository->findAll()]); } /** * Odstraní článek podle jeho URL. * @param string|null $url URL článku * @return Response HTTP odpověď * @Route("/odstranit/{url}", name="remove_article") * @throws ORMException Jestliže nastane chyba při mazání článku. */ public function remove(string $url = null): Response { $this->articleRepository->removeByUrl($url); $this->addFlash('notice', 'Článek byl úspěšně odstraněn.'); return $this->redirectToRoute('article_list'); } /** * Vytváří a zpracovává formulář pro editaci článku podle jeho URL. * @param string|null $url URL článku * @param Request $request HTTP požadavek * @return Response HTTP odpověď * @Route("/editor/{url}", name="article_editor") * @throws ORMException Jestliže nastane chyba při ukládání článku. */ public function editor(Request $request, string $url = null): Response { if ($url) { // Pokud byla zadána URL, pokusí se načíst článek podle ní. if (!($article = $this->articleRepository->findOneByUrl($url))) { // Pokud se článek s danou URL nepodaří najít, vypíše chybovou hlášku a vytvoří nový s danou URL. $this->addFlash('warning', 'Článek se zadanou URL nebyl nalezen!'); $article = (new Article())->setUrl($url); } } else $article = new Article(); // Jinak se nejedná o editaci článku a vytváří se nový článek. // Vytváření editačního formuláře podle entity článku. $editorForm = $this->createFormBuilder($article) ->add('title', null, ['label' => 'Titulek']) ->add('url', null, ['label' => 'URL']) ->add('description', null, ['label' => 'Popisek']) ->add('content', null, ['label' => 'Obsah', 'required' => false]) ->add('submit', SubmitType::class, ['label' => 'Uložit článek']) ->getForm(); // Zpracování editačního formuláře. $editorForm->handleRequest($request); if ($editorForm->isSubmitted() && $editorForm->isValid()) { $this->articleRepository->save($article); $this->addFlash('notice', 'Článek byl úspěšně uložen.'); return $this->redirectToRoute('article', ['url' => $article->getUrl()]); } // Předání editačního formuláře do šablony. return $this->render('article/editor.html.twig', ['editorForm' => $editorForm->createView()]); } /** * Načte článek podle jeho URL a předá jej do šablony. * Pokud není zadaná URL, nastaví se jí hodnota pro výchozí článek. * @param Article $article článek * @return Response HTTP odpověď * @throws NotFoundHttpException Jestliže článek s danou URL nebyl nalezen. * @Route("/{url?%default_article_url%}", name="article") * @Entity("article", expr="repository.findOneByUrl(url)") */ public function index(Article $article): Response { return $this->render('article/index.html.twig', ['article' => $article]); } }
Nyní by asi bylo dobré si uvedený kód trochu popsat. V první řadě jsme přidali následující akce i s pravidly pro routování, které využívají našeho repositáře článků:
listAction()
- Vypisuje seznam všech článků.removeAction()
- Odstraní vybraný článek.editorAction()
- Umožňuje vytvářet nové i editovat stávající články.
Dále jsme sjednotili získání repositáře pro správu článků pomocí DI napříč všemi těmito metodami a to pomocí principů OOP, konkrétně privátního atributu a konstruktoru.
Nakonec stojí asi za povšimnutí formulář pro vytváření a editaci
článků, který jsme postavili na naší entitě Article
, takže
využívá jejích validačních pravidel a automaticky nám tak dovolí uložit
pouze článek s validními daty.
Konfigurace
Ještě než se přesuneme k samotným šablonám, přidáme jednu drobnou vychytávku do konfigurace.
config/packages/twig.yaml
Naučíme totiž všechny formuláře v naší aplikaci používat výchozí Twig šablonu pro jejich vykreslování:
twig: default_path: '%kernel.project_dir%/templates' # Nastaví všem formulářům v aplikaci tuto šablonu pro vykreslování. form_themes: - 'form/fields.html.twig'
Šablony
Nyní se podíváme na šablony k jednotlivým akcím.
templates/form/fields.html.twig
Začneme definicí oné šablony pro vykreslení jednoho obecného formulářového elementu:
{# Vlastní definice vzhledu jednoho řádku formuláře. #} {% block form_row %} <div> {{ form_errors(form) }}<br> {{ form_label(form) }}<br> {{ form_widget(form) }} </div> {% endblock form_row %}
Šablonu si samozřejmě můžete upravit dle libosti k dosažení vašeho oblíbeného vzhledu.
templates/article/editor.html.twig
Nyní následuje šablona pro editor článků. Zde si povšimněte jak jednoduše jsme zařídili vykreslení formuláře i s naší vlastní šablonou a dále způsobu přidávání dalších JavaScript knihoven:
{% extends 'base.html.twig' %} {% block title %}Editor{% endblock %} {% block description %}Editor článků.{% endblock %} {% block body %} {# Formulář pro editaci článku. #} {{ form(editorForm) }} {% endblock %} {% block javascripts %} {{ parent() }} <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/tinymce/5.5.1/tinymce.min.js"></script> <script type="text/javascript"> tinymce.init({ selector: '#form_content', plugins: [ 'advlist autolink lists link image charmap print preview anchor', 'searchreplace visualblocks code fullscreen', 'insertdatetime media table contextmenu paste' ], toolbar: 'insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image', entities: '160,nbsp', entity_encoding: 'raw' }); </script> {% endblock %}
templates/article/list.html.twig
Dále přidáme šablonu pro výpis článků:
{% extends 'base.html.twig' %} {% block title %}Výpis článků{% endblock %} {% block description %}Výpis všech článků.{% endblock %} {% block body %} <table> {% for article in articles %} <tr> <td> <h2><a href="{{ path('article', {'url': article.url}) }}">{{ article.title }}</a></h2> {{ article.description }} <br/> <a href="{{ path('article_editor', {'url': article.url}) }}">Editovat</a> <a href="{{ path('remove_article', {'url': article.url}) }}">Odstranit</a> </td> </tr> {% endfor %} </table> {% endblock %}
templates/base.html.twig
Na závěr přidáme ještě odkazy do výchozí šablony. Nebudu ji sem již vypisovat znovu celou, pouze změny:
... <nav> <ul> <li><a href="{{ path('article') }}">Úvod</a></li> <li><a href="{{ path('article_list') }}">Seznam článků</a></li> <li><a href="#">Kontakt</a></li> </ul> </nav> ...
Nyní se již můžeme podívat na výsledek. Zkusíme si editovat úvodní článek kliknutím na odkaz "Editovat":

Můžeme si článek zkusit i následně odebrat (ale pozor, zatím nemáme metodu pro přidání článku):

Pro dnešní lekci to ale bude vše
V další lekci, Jednoduchý redakční systém v Symfony - Kontaktní formulář, přidáme ContactControler
a
příslušné šablony.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 74x (55.8 kB)
Aplikace je včetně zdrojových kódů v jazyce PHP