Lekce 1 - Rezervační systém v Symfony - Založení projektu a přihlášení
Zdravím všechny pokročilejší programátory v kurzu tutoriálů pro PHP framework Symfony.
Budeme zde programovat rezervační systém pro vozidla. K dispozici bude samozřejmě základní bezpečnost přihlášením emailem a heslem, uživatelské role (admin, běžný uživatel), přidávání vozidel, jejich úprava a mnoho dalšího.
Na větším projektu nás potkají nové problémy, se kterými jsme se ještě nesetkali, a ukážeme si jejich řešení.
Pokud za sebou nemáte naše minulé lekce a nebo právě začínáte se Symfony, doporučuji se prvně podívat na kurz Základy frameworku Symfony.
Příprava projektu
Nejprve si připravíme celý projekt. Jelikož je vydána Symfony verze 5, založíme si projekt nad touto verzí. Začneme s požadavky pro tuto verzi Symfony. Nainstalujeme si PHP verzi 7.2.5 a vyšší. Dále budeme potřebovat composer pro instalaci balíků a samotného frameworku a samozřejmě databázi.
Pozor, dodržuj přesné verze komponent! Pokročilé projekty jako tento jsou složené z komponent. Možná by tě napadlo použít nejnovější verzi nějaké komponenty, co zrovna včera vyšla. Projekt ti pak ale bez odborné úpravy pravděpodobně nebude fungovat! U verzí komponent neplatí jako např. u aktualizace Windows, že chceme každý den používat tu nejnovější. Neustálé aktualizace všeho by totiž vyžadovaly každodenní a komplexní změny kódu projektu a reálně se tak neprovádějí. Ze stejného důvodu i my aktualizujeme kurzy v pravidelných intervalech a nové verze k sobě pak sladíme tak, aby vše fungovalo.
Symfony CLI
Symfony CLI (nebo příkazový řádek Symfony) nám pomůže například vytvořením vestavěného serveru. Na instalaci Symfony CLI je třeba nástroj Scoop. Scoop nainstalujeme tak, že zapneme Powershell v OS Windows a vložíme následující příkaz:
iwr -useb get.scoop.sh | iex
Následně spustíme v příkazovém řádku příkaz:
scoop install symfony-cli
Nyní máme Symfony CLI nainstalované Všechny příkazy, co zde uvedu a
budou začínat slovem symfony
, využije se Symfony CLI.
Ostatní OS
Na OS Linux nebo MacOS je popsána instalace v dokumentaci Symfony CLI.
Symfony projekt
Pokud máme vše připraveno, vytvoříme si pro projekt složku a v ní zahájíme instalaci Symfony následujícím příkazem:
composer create-project symfony/website-skeleton:"^5" rezervace_vozidel
Nyní se v aktuálním adresáři vytvořila složka
rezervace_vozidel
s projektem, která má následující
strukturu:
Instalace určitých verzí může být někdy problém, proto jsem nahrál tuto základní složku pod článek.
Pokud používáme Symfony CLI, můžeme použít následující příkaz a ujistit se, zda splňujeme požadavky:
symfony check:requirements
Požadavky splňuje pouze právě použitý PC, kde příkaz proběhl. Pokud budete projekt někde nahrávat, je vhodné se ujistit i tam.
Jestli jste zvyklí využívat vlastní balík pro webový server (wamp/xampp), tak ho můžete využít. Symfony však může udělat svůj vlastní webový server, který není třeba dále konfigurovat, ten případně spustíme příkazem:
symfony server:start
V příkazovém řádku se dozvíme adresu s portem, kterou navštívíme ve webovém prohlížeči. Tím se zobrazí uvítací homepage Symfony.
Se zakládáním nového projektu byste neměli mít problém, případně opět doporučím nejdříve projít základní kurz, konkrétně vytvoření projektu v lekci Instalace Symfony a IDE.
Databáze
Databázový server je třeba mít už nainstalovaný a spuštěný. Nejprve
řekneme Symfony, kde je naše databáze a jak se k ní připojí. Otevřeme si
soubor .env
v root složce projektu a najdeme řádek:
DATABASE_URL=mysql://db_user:[email protected]:3306/db_name?serverVersion=5.7
Údaje na tomto řádku následně změníme na údaje našeho serveru.
Nezapomeňte uvést verzi vašeho databázového serveru. V mém případě to
bude uživatel root
a heslo kokos123
, verze MySQL
5.7
:
DATABASE_URL=mysql://root:[email protected]:3306/itnetwork_tut?serverVersion=5.7
Pokud používáte databázi SQLite nebo PostgreSQL, URL je jiná! Dočtete se o tom o řádek
výše v .env
souboru.
Nyní si můžeme nechat vytvořit databázi projektu pomocí příkazu:
php bin/console doctrine:database:create
Přihlášení a uživatelé
Dalším základním kamenem aplikace jsou uživatelé.
Entita User
Nejprve si vytvoříme entitu User
, která bude reprezentovat
uživatele. Uděláme to pomocí příkazu:
php bin/console make:user
Ve vygenerovaném souboru src/Entity/User.php
ještě přidáme
uživateli vlastnosti $canReserve
a $displayname
.
Soubor bude vypadat takto:
<?php namespace App\Entity; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Security\Core\User\UserInterface; /** * @ORM\Entity(repositoryClass="App\Repository\UserRepository") */ class User implements UserInterface { /** * @ORM\Id() * @ORM\GeneratedValue() * @ORM\Column(type="integer") */ private $id; /** * @ORM\Column(type="string", length=180, unique=true) */ private $email; /** * @ORM\Column(type="json") */ private $roles = []; /** * @var string The hashed password * @ORM\Column(type="string") */ private $password; /** * @ORM\Column(type="string", length=255, nullable=true) */ private $displayname; /** * @ORM\Column(type="boolean") **/ private $canReserve; public function getId(): ?int { return $this->id; } public function getEmail(): ?string { return $this->email; } public function setEmail(string $email): self { $this->email = $email; return $this; } /** * A visual identifier that represents this user. * * @see UserInterface */ public function getUsername(): string { return (string) $this->email; } /** * @see UserInterface */ public function getRoles(): array { $roles = $this->roles; // guarantee every user at least has ROLE_USER $roles[] = 'ROLE_USER'; return array_unique($roles); } public function setRoles(array $roles): self { $this->roles = $roles; return $this; } /** * @see UserInterface */ public function getPassword(): string { return (string) $this->password; } public function setPassword(string $password): self { $this->password = $password; return $this; } /** * @see UserInterface */ public function getSalt() { // not needed when using the "bcrypt" algorithm in security.yaml } /** * @see UserInterface */ public function eraseCredentials() { // If you store any temporary, sensitive data on the user, clear it here // $this->plainPassword = null; } public function getDisplayname(): ?string { return $this->displayname; } public function setDisplayname(?string $displayname): self { $this->displayname = $displayname; return $this; } public function getCanReserve(): ?bool { return $this->canReserve; } public function setCanReserve(bool $canReserve): self { $this->canReserve = $canReserve; return $this; } }
Autentifikace
Ověřovat uživatele budeme pomocí emailu a hesla.
Necháme si vytvořit také LoginFormAuthenticator
(/logout
, LoginForm.php
a
SecurityController.php
) přes příkaz:
php bin/console make:auth
Všechny naše nové soubory jsou tedy následující:
src/Entity/User.php src/Repository/UserRepository.php src/Security/LoginFormAuthenticator.php templates/security/login.html.twig
config/packages/security.yaml
Symfony si automaticky nakonfiguroval soubory
config/packages/doctrine.yaml
a
config/packages/security.yaml
, které jsme mu zadali do
příkazového řádku. Avšak nikdo nemá zatím přístup k přihlášení na
adrese /login
. Na konec souboru security.yaml
tedy
přidáme řádek, který nám zajistí, že budou mít všichni přístup k
přihlášení:
access_control: - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
Migrace
Teď máme adresu /login
"funkční". Nebudeme se ale moci
přihlásit, protože nemáme zatím žádné uživatele a hlavně jsme
neprovedli migraci databáze. Sice tedy máme entitu, ale v databázi reálně
tabulka s uživateli ještě není. Pro migraci spustíme tyto dva
příkazy:
php bin/console make:migration php bin/console doctrine:migrations:migrate
Testování
Abychom projekt vyvíjeli trochu na úrovni, testovat uživatele (vytvářet "umělé entity") budeme pomocí fixtures, které využijeme i v budoucnu (např. pro rezervace). Nainstalujeme si je pomocí:
composer require --dev doctrine/doctrine-fixtures-bundle
a poté vytvoříme novou fixture:
php bin/console make:fixtures
Fixturu nazveme UserFixture
, bude mít na starosti uživatele.
Soubor src/DataFixtures/UserFixture.php
upravíme do následující
podoby:
<?php namespace App\DataFixtures; use App\Entity\User; use Doctrine\Bundle\FixturesBundle\Fixture; use Doctrine\Common\Persistence\ObjectManager; use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; class UserFixture extends Fixture { public const USER_USER_REFERENCE = 'user-user'; public const USER_ADMIN_REFERENCE = 'user-admin'; private $encoder; public function __construct(UserPasswordEncoderInterface $encoder) { $this->encoder = $encoder; } public function load(ObjectManager $manager) { $user1 = new User(); $user1->setPassword($this->encoder->encodePassword($user1, "kokos1")); $user1->setCanReserve(0); // otestujeme i to, že admin bude ignorovat tuto vlastnost $user1->setDisplayname("Admin"); $user1->setEmail("[email protected]"); $user1->setRoles(["ROLE_ADMIN"]); $user2 = new User(); $user2->setPassword($this->encoder->encodePassword($user2, "kokos1")); $user2->setCanReserve(0); $user2->setDisplayname("Test"); $user2->setEmail("[email protected]"); $user2->setRoles(["ROLE_USER"]); // díky tomuto se pak dostaneme k těmto uživatelům z jiných fixtur $this->addReference(self::USER_ADMIN_REFERENCE, $user1); $this->addReference(self::USER_USER_REFERENCE, $user2); $manager->persist($user1); $manager->persist($user2); $manager->flush(); } }
Fixtura vytvoří v databázi 2 testovací uživatele. Určitě jste si všimli, že jeden je administrátor a druhý jen běžný uživatel. To abychom si mohli ověřit, že funkce aplikace pro administrátora fungují a zároveň nejsou dostupné pro běžného uživatele. To je konec konců velmi důležité!
Nakonec spustíme a potvrdíme příkaz pro nahrání uživatelů do databáze:
php bin/console doctrine:fixtures:load
Závěr
Nyní se můžeme přihlásit na adrese /login
Vyhodí nám to chybu "TODO:
provide a valid redirect inside". Zatím se nemáme kam přihlásit, proto
budeme myslet do budoucna a odkážeme na budoucí routu /myBooking
v metodě onAuthenticationSuccess
v souboru
src/Security/LoginFormAuthenticator.php
následovně:
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey) { if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) { return new RedirectResponse($targetPath); } // TODO: redirect after authentication For example : return new RedirectResponse($this->urlGenerator->generate('some_route')); return new RedirectResponse($this->urlGenerator->generate("myBooking")); }
Tady ukončíme dnešní lekci.
V další lekci, Rezervační systém v Symfony - Entity, repositáře, kontrolery, si vytvoříme entity rezervace, vozidla, kontroler a upravíme repositář pro rezervace.
Měl jsi s čímkoli problém? Zdrojový kód vzorové aplikace je ke stažení každých pár lekcí. Zatím pokračuj dál, a pak si svou aplikaci porovnej se vzorem a snadno oprav.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkamiStaženo 227x (13.76 MB)