Přidej si svou IT školu do profilu a najdi spolužáky zde na síti :)

6. díl - Jednoduchý redakční systém v Symfony - Model článků

PHP Symfony Základy Jednoduchý redakční systém v Symfony - Model článků

ONEbit hosting Unicorn College Tento obsah je dostupný zdarma v rámci projektu IT lidem. Vydávání, hosting a aktualizace umožňují jeho sponzoři.

Vítám vás všechny u pokračování seriálu tutoriálů o tvorbě webových aplikací v PHP frameworku Symfony. V minulé lekci, Jednoduchý redakční systém v Symfony - Struktura projektu, jsme si připravili projektovou strukturu pro jednoduchý redakční systém a jak jsem slíbil, dnes se rovnou bez zbytečných řečí vrhneme na implementaci. Takže jdeme na to! :)

Databáze

V první řadě se podíváme na nastavení i obsah databáze. V Symfony se standardně pro práci s databází používá knihovna třetích stran Doctrine. Ta pracuje s principem Objektově Relačního Mapování (ORM), jehož základ tvoří entity. S jednou takovou jsme se již setkali ve 4. lekci kurzu při tvorbě operace kalkulačky.

src/AppBundle/En­tity/Article.php

Nyní si obdobně vytvoříme entitu reprezentující články v našem redakčním systému, následně ji obohatíme o anotace z Doctrine knihovny a necháme si podle ní vygenerovat celou relační databázovou strukturu. Doctrine potom zajistí, že položky z naší databáze v dané tabulce se automaticky namapují na instance oné entitní třídy (tedy na objekty), což je právě princip celého ORM.

<?php

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * Reprezentuje záznamy databázové tabulky článků v redakčním systému.
 * @package AppBundle\Entity
 * @ORM\Entity(repositoryClass="AppBundle\Repository\ArticleRepository")
 * @ORM\Table(name="article")
 */
class Article
{
        /**
         * @var int Unikátní ID článku.
         * @ORM\Id
         * @ORM\GeneratedValue
         * @ORM\Column(type="integer")
         */
        private $id;

        /**
         * @var string Titulek článku.
         * @ORM\Column(type="string")
         * @Assert\NotBlank(message="Titulek článku nemůže být prázdný!")
         */
        private $title;

        /**
         * @var string Text (obsah) článku.
         * @ORM\Column(type="text")
         * @Assert\NotBlank(message="Obsah článku nemůže být prázdný!")
         */
        private $content;

        /**
         * @var string Unikátní URL adresa článku.
         * @ORM\Column(type="string", unique=true)
         * @Assert\NotBlank(message="URL adresa článku nemůže být prázdná!")
         */
        private $url;

        /**
         * @var string Krátký popis článku.
         * @ORM\Column(type="string")
         * @Assert\NotBlank(message="Popis článku nemůže být prázdný!")
         */
        private $description;

        /**
         * Getter pro ID článku.
         * @return int ID článku
         */
        public function getId()
        {
                return $this->id;
        }

        /**
         * Setter pro ID článku.
         * @param int $id ID článku
         */
        public function setId($id)
        {
                $this->id = $id;
        }

        /**
         * Getter pro titulek článku.
         * @return string titulek článku
         */
        public function getTitle()
        {
                return $this->title;
        }

        /**
         * Setter pro titulek článku.
         * @param string $title titulek článku
         */
        public function setTitle($title)
        {
                $this->title = $title;
        }

        /**
         * Getter pro obsah článku.
         * @return string obsah článku
         */
        public function getContent()
        {
                return $this->content;
        }

        /**
         * Setter pro obsah článku.
         * @param string $content obsah článku
         */
        public function setContent($content)
        {
                $this->content = $content;
        }

        /**
         * Getter pro URL adresu článku.
         * @return string URL adresa článku
         */
        public function getUrl()
        {
                return $this->url;
        }

        /**
         * Setter pro URL adresu článku.
         * @param string $url URL adresa článku
         */
        public function setUrl($url)
        {
                $this->url = $url;
        }

        /**
         * Getter pro popis článku.
         * @return string popis článku
         */
        public function getDescription()
        {
                return $this->description;
        }

        /**
         * Setter pro popis článku.
         * @param string $description popis článku
         */
        public function setDescription($description)
        {
                $this->description = $description;
        }
}

Pozn.: Třídu si můžete nechat i předgenerovat a to příkazem:

php bin/console doctrine:generate:entity

Všimněte si zde hlavně nových ORM anotací, které "transformují" onu třídu na příslušnou databázovou tabulku a její atributy na sloupce oné tabulky s daným typem a vlastnostmi.

Dále si můžete povšimnou, že jsme si zde rovnou připravili i anotace, které využijeme při tvorbě formuláře pro práci s články, který tím pádem můžeme také vytvořit na základě této entity ;)

Nastavení přístupových údajů a vytvoření databáze

Abychom si nyní mohli nechat vygenerovat databázovou strukturu, musíme ještě nastavit přístupové údaje do naší databáze. Pokud jste tak již neučinili při instalaci projektu přes Composer, doplňte je nyní do souboru app/config/pa­rameters.yml, který by měl vypadat nějak takto:

# This file is auto-generated during the composer install
parameters:
    database_host: localhost
    database_port: 3306
    database_name: <název databáze>
    database_user: <uživatelské jméno>
    database_password: <heslo>
    mailer_transport: smtp
    mailer_host: localhost
    mailer_user: ~
    mailer_password: ~
    secret: ThisTokenIsNotSoSecretChangeIt

Databázi poté nemusíte vytvářet ručně, ale pro její vytvoření můžete použít Doctrine příkaz:

php bin/console doctrine:database:create

Generování databázové struktury

Pro vygenerování naší relační databázové struktury v podobě jedné tabulky článků nám bude opět stačit pouze Doctrine příkaz:

php bin/console doctrine:schema:update --force

Tento příkaz můžete následně opakovaně používat i pro synchronizaci změn v entitách přímo do existujícího databázové struktury, ale pozor na již existující data.

Pokud jste vše udělali dobře, měli byste v nastavené databázi vidět novou tabulku article.

Pozn.: Pokud si chcete vypsat všechny Doctrine příkazy a jejich popis, použijte příkaz:

php bin/console list doctrine

Předpřipravené články

My si do naší tabulky článků doplníme ještě dva předpřipravené články, jeden pro úvodní stránku a jeden pro vypsání chyby. To bývá standardem u většiny redakčních systémů.

Podle oficiálního postupu bych si pro tyto články měl připravit tzv. Doctrine Fixture. To by ale vyžadovalo instalaci externího bundlu DoctrineFixtu­resBundle, ale toho vás chci prozatím ušetřit a tak jsem to vyřešil pouhým SQL skriptem, který stačí spustit nad vaší databází:

INSERT INTO `article` VALUES ('1', 'Úvod', '<p>Vítejte na našem webu!</p>\r\n\r\n<p>Tento web je postaven na <strong>jednoduchém redakčním systému v Symfony frameworku</strong>. Toto je úvodní článek, načtený z databáze.</p>', 'uvod', 'Úvodní článek na webu v Symfony v PHP');
INSERT INTO `article` VALUES ('2', 'Stránka nebyla nalezena', '<p>Litujeme, ale požadovaná stránka nebyla nalezena. Zkontrolujte prosím URL adresu.</p>', 'chyba', 'Stránka nebyla nalezena.');

Model

Přesuneme se k vytváření modelu. Třídám v modelové vrstvě, které mají pracovat s Doctrine entitami, se říká repositáře. To je trochu rozdíl oproti modelu kalkulačky, ale v podstatě je pouze kosmetický.

src/AppBundle/Re­pository/Arti­cleRepository­.php

Nyní si tedy vytvoříme repositář pro správu článků:

<?php

namespace AppBundle\Repository;

use AppBundle\Entity\Article;
use Doctrine\ORM\EntityRepository;

/**
 * Repositář pro správu článků v redakčním systému.
 * @package AppBundle\Repository
 */
class ArticleRepository extends EntityRepository
{
        /**
         * Vrátí seznam článků v databázi.
         * @return Article[] seznam článků
         */
        public function getArticles()
        {
                return $this->findAll();
        }

        /**
         * Vrátí článek z databáze podle jeho URL.
         * @param string $url URl článku
         * @return null|Article první článek, který odpovídá URL nebo null při neúspěchu
         */
        public function getArticle($url)
        {
                return $this->findOneByUrl($url);
        }

        /**
         * Uloží článek do systému. Pokud není nastaveno ID, vloží nový, jinak provede editaci.
         * @param Article $article článek
         */
        public function saveArticle(Article $article)
        {
                $this->getEntityManager()->persist($article);
                $this->getEntityManager()->flush($article);
        }

        /**
         * Odstraní článek.
         * @param string $url URL článku
         */
        public function removeArticle($url)
        {
                if (($article = $this->getArticle($url))) {
                        $this->getEntityManager()->remove($article);
                        $this->getEntityManager()->flush();
                }
        }
}

Důležité je zmínit, že každý repositář dědí ze třídy EntityRepository, která mu umožňuje pracovat s entitami, vybírat je, ukládat i mazat z databáze. Každá instance třídy Article pak reprezentuje jeden záznam v databázi.

Co stojí za povšimnutí je, že ukládání nebo mazání entity bychom měli ještě potvrdit voláním flush().

To je z dnešního dílu všechno, příště se budeme věnovat kontrolerům, šablonám, či zavádění konfigurace přímo do AppBundlu. Tím náš projekt zprovozníme. :)


 

 

Článek pro vás napsal Jindřich Máca
Avatar
Jak se ti líbí článek?
3 hlasů
Autor se věnuje převážně webovým technologiím, ale má velkou zálibu ve všem vědeckém, nejen ze světa IT. :-)
Aktivity (4)

 

 

Komentáře

Avatar
josef.nuhlicek:22. června 15:09

Děkuji za velice podnětný seriál. Jenom se zeptám, k tomu generování struktury tabulky z konzole, neměl by tam být spíš příkaz

php bin/console doctrine:schema:update --force

Protože po tom příkazu, co je uveden v článku, to pouze vypíše nápovědu, a bez toho ... help ... to zase pouze vytváří novou databázi, bez tabulky...

 
Odpovědět 22. června 15:09
Avatar
Jindřich Máca
Tým ITnetwork
Avatar
Odpovídá na josef.nuhlicek
Jindřich Máca:22. června 21:00

V první řadě jsem rád, že se seriál líbí. :)

Co se týče příkazů, tak to help byl rozhodně překlep, který jsem hned opravil. Ani nevím, jak se to tam dostalo. :D

Jinak tedy příkaz

php bin/console doctrine:database:create

se používá pro vytvoření celé nové databáze podle Symfony konfigurace a příkaz

php bin/console doctrine:schema:update --force

se pak používá pro synchronizaci aktuálních entit se schématem dané databáze.

Takže děkuji za dobrou připomínku, hned jsem to do seriálu také doplnil.

Každopádně více informací můžete nalézt samozřejmě přímo v oficiální dokumentaci - http://symfony.com/…octrine.html ;)

 
Odpovědět 22. června 21:00
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 2 zpráv z 2.