Pavel Zaněk PavelZanek.com
Vyberte jazyk

Jak efektivně vytvořit systém pro přihlášení k newsletteru v Laravelu: od základů až po testování

Článek poskytuje komplexní průvodce vytvářením systému pro přihlášení k odběru novinek v Laravelu. Seznámíte se s tvorbou databázových modelů, e-mailových šablon, překladů a testováním pomocí Pest.

Publikováno 21.06.2023 od Pavel Zaněk

Odhadovaná doba čtení: 27 minut

Jak efektivně vytvořit systém pro přihlášení k newsletteru v Laravelu: od základů až po testování

Obsah článku

Vítejte v tomto rozsáhlém průvodci, kde se podíváme na to, jak efektivně vytvořit systém pro přihlášení k newsletteru v Laravelu. Laravel je silný a flexibilní framework pro PHP, který se hodí pro širokou škálu aplikací, včetně tvorby funkčního a přizpůsobivého newsletteru.

V dnešní době jsou newslettery jedním z nejdůležitějších nástrojů pro komunikaci se zákazníky nebo uživateli webové stránky. Ať už poskytujete informace o novinkách, vzdělávacích materiálech nebo speciálních nabídkách, je důležité, aby Váš systém pro odběr newsletteru byl snadno použitelný a efektivní.

Tento průvodce vás provede celým procesem vytváření takového systému v Laravelu, od základní přípravy databázové továrny, přes vytváření šablony pro email a Livewire komponenty, až po nastavení trasování. V neposlední řadě se podíváme na důležitost překladů a internacionalizaci a na to, jak toho v Laravelu docílit.

Samozřejmě, jakýkoliv vývoj by měl být doprovázen kvalitním testováním, a tak se také zaměříme na to, jak napsat efektivní testy pomocí nástroje Pest.

Pojďme tedy na to a zjistěte, jak vytvořit skvělý systém pro přihlášení k newsletteru v Laravelu! 

Příprava databázové továrny

Pro práci s daty v Laravelu je jednou z nezbytných předpokladů příprava databázové továrny, která nám poskytne rámec pro manipulaci s daty a umožní nám efektivně a bezpečně pracovat s naší databází.

V rámci tohoto průvodce budeme pracovat s jedním konkrétním modelem - NewsletterUser. Tento model bude reprezentovat jednotlivé uživatele, kteří se přihlásí k odběru našeho newsletteru.

Prvním krokem je vytvoření továrny pro náš model. Sice tento postup není obvyklý, nabídne Vám ale lepší představu o tom, co bude model obsahovat. Továrna nám umožní generovat testovací data pro naše účely. Pomocí ní budeme moci snadno vytvářet instance našeho modelu NewsletterUser s náhodně generovanými daty, což se nám při zavěrečném testování bude hodit.

V Laravelu je tvorba továrny velmi jednoduchá. Stačí použít Artisan příkaz make:factory, který automaticky vygeneruje kostru továrny pro náš model.

php artisan make:factory NewsletterUserFactory --model=NewsletterUser

Tím vytvoříme novou třídu NewsletterUserFactory, kterou následně upravíme pro naše potřeby. V našem případě bude třeba nastavit alespoň následující atributy: email, language, verification_token a is_verified.

Výsledná třída by mohla vypadat následovně:

<?php

namespace Database\Factories\Newsletter;

use App\Enums\Newsletter\NewsletterLanguage;
use App\Models\Newsletter\NewsletterUser;
use Illuminate\Database\Eloquent\Factories\Factory;

class NewsletterUserFactory extends Factory
{
    protected $model = NewsletterUser::class;

    public function definition()
    {
        return [
            'email' => $this->faker->email(),
            'language' => NewsletterLanguage::ENGLISH,
            'is_verified' => false,
        ];
    }
}

Tato továrna nám nyní umožní vytvářet testovací instance našeho modelu NewsletterUser s náhodnými daty. To se nám bude hodit při dalším vývoji a testování našeho systému pro přihlášení k newsletteru.

Migrace databáze

Migrace je klíčová součást Laravelu, která nám umožňuje vytvořit strukturu naší databáze přímo z našeho kódu. Vytvořme tedy migraci pomocí artisan příkazu:

php artisan make:migration create_newsletter_users_table

V našem případě jsme vytvořili migraci pro model NewsletterUser, který obsahuje všechny nezbytné informace pro správu odběratelů newsletteru, jako je email, jazyk a stav ověření.

<?php

use App\Enums\Newsletter\NewsletterLanguage;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('newsletter_users', function (Blueprint $table) {
            $table->id();
            $table->string('email', 128)->unique();
            $table->string('language', 6)->default(NewsletterLanguage::ENGLISH->value);
            $table->boolean('is_verified')->default(false);
            $table->string('verification_token', 60)->nullable();
            $table->timestamps();
            $table->softDeletes();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('newsletter_users');
    }
};

Díky migraci můžeme snadno vytvářet, modifikovat i mazat tabulky v databázi, což je velmi užitečné při vývoji aplikace a distribuci mezi různými prostředími. Navíc, Laravel automaticky sleduje, jaké migrace již byly aplikovány, takže nemusíme řešit jejich opakované spouštění.

Vytvoření šablony pro email

Když uživatel zadá svůj email a vybere preferovaný jazyk newsletteru, potřebujeme mu poslat ověřovací email. Ten obsahuje ověřovací odkaz, na který musí uživatel kliknout pro ověření svého emailu. Pro tento účel budeme potřebovat vytvořit emailovou šablonu.

Laravel opět nabízí velmi pohodlnou práci s emailovými šablonami. Začneme tím, že vytvoříme novou třídu pro naši emailovou notifikaci pomocí Artisan příkazu:

php artisan make:mail NewsletterVerificationMail --markdown=emails.newsletter-verification

Tímto příkazem jsme vytvořili novou třídu NewsletterVerificationMail a zároveň jsme Laravelu řekli, že chceme použít markdown formát pro vytvoření naší emailové šablony. Laravel za nás automaticky vytvořil soubor pro tuto šablonu v adresáři resources/views/emails.

Nyní můžeme tuto šablonu upravit podle našich potřeb. V našem případě si pro ukázku potřebujeme v emailu zobrazit několik informací:

  1. Uvítací zprávu
  2. Ověřovací odkaz
  3. Tlačítko pro přesměrování na naši webovou stránku

Výsledná šablona by mohla vypadat následovně:

<x-mail::message>
# {{ __('template.newsletter-email-verification-headline') }}

{{ __('template.newsletter-email-verification-description') }}
 
<x-mail::button :url="$signedUrl">
    {{ __('template.newsletter-email-verification-verify-button') }}
</x-mail::button>

<x-mail::button :url="$homepageUrl">
    {{ __('template.newsletter-email-verification-homepage-button') }}
</x-mail::button>
 
{{ __('template.newsletter-email-verification-thanks') }},<br>
{{ config('app.name') }}
</x-mail::message>

V této šabloně jsme použili Laravelovské komponenty mail::message a mail::button, které nám umožňují snadno vytvořit strukturu našeho emailu. Texty jsou načítány z překladových souborů, takže můžeme snadno přepínat mezi různými jazyky podle toho, jaký jazyk si uživatel zvolil.

Nakonec je třeba tuto šablonu použít v naší třídě NewsletterVerificationMail:

<?php

namespace App\Mail\App\Guest\Newsletter;

use App\Models\Newsletter\NewsletterUser;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\URL;

class NewsletterVerificationMail extends Mailable
{
    use Queueable, SerializesModels;

    public NewsletterUser $newsletterUser;

    public function __construct(NewsletterUser $newsletterUser)
    {
        $this->newsletterUser = $newsletterUser;
    }

    /**
     * Get the message envelope.
     */
    public function envelope(): Envelope
    {
        return new Envelope(
            subject: __('template.newsletter-email-verification-subject') . ' | PavelZanek.com',
        );
    }

    /**
     * Get the message content definition.
     *
     * @return \Illuminate\Mail\Mailables\Content
     */
    public function content()
    {
        $signedUrl = URL::signedRoute('newsletter.verify-user', [
            'language' => $this->newsletterUser->language,
            'token' => $this->newsletterUser->verification_token
        ]);

        return new Content(
            markdown: 'emails.app.guest.newsletter.verification-mail',
            with: [
                'newsletterUser' => $this->newsletterUser,
                'signedUrl' => $signedUrl,
                'homepageUrl' => route('homepage', ['language' => 'en']),
            ],
        );
    }
}

Zde není potřeba detailněji rozebírat ukázku kódu, využijeme poskytnutá data a nastavíme předmět emailu.

Vytvoření Livewire komponenty

Livewire je vynikající nástroj pro tvorbu dynamických komponent v Laravelu, který umožňuje snadno spojit JavaScript a PHP. Jeho hlavní výhodou je, že nevyžaduje znalost JavaScriptu a vše můžeme řešit přímo v PHP.

V našem případě využijeme Livewire komponentu pro tvorbu formuláře pro přihlášení k odběru newsletteru.

Nejdříve vytvoříme novou Livewire komponentu pomocí Artisan příkazu:

php artisan make:livewire NewSubscriberForm

Tímto vytvoříme dva nové soubory - NewSubscriberForm.php a new-subscriber-form.blade.php. První je třída, kde definujeme logiku komponenty. Druhá je šablona, která popisuje, jak komponenta vypadá.

V NewSubscriberForm.php třídě definujeme dva veřejné atributy - $email a $language, které představují hodnoty zadané uživatelem v našem formuláři. Dále zde musíme vytvořit metodu subscribe(), která se zavolá po odeslání formuláře.

<?php

namespace App\Http\Livewire\Guest\Newsletter;

use App\Actions\Guest\Newsletter\CreateNewsletterUserAction;
use App\Enums\Newsletter\NewsletterLanguage;
use App\Mail\App\Guest\Newsletter\NewsletterVerificationMail;
use Illuminate\Support\Facades\Mail;
use Illuminate\Validation\Rules\Enum;
use Livewire\Component;

class NewSubscriberForm extends Component
{
    public string $email = '';
    public string $language = '';

    public function render()
    {
        return view('livewire.guest.newsletter.subscription-form');
    }

    public function subscribe()
    {
        $validatedData = $this->validate([
            'email' => 'required|email|max:128|unique:newsletter_users,email',
            'language' => [
                'required',
                'string',
                'max:6',
                new Enum(NewsletterLanguage::class),
            ],
        ]);

        $newsletterUser = (new CreateNewsletterUserAction())->execute($validatedData);

        // Send verification email
        Mail::to($this->email)
            ->locale($this->language)
            ->send(new NewsletterVerificationMail($newsletterUser));

        $this->reset('email');

        $this->dispatchBrowserEvent('alert',[
            'type'=> 'success',
            'message'=> __('template.newsletter-waiting-for-validation')
        ]);
    }
}

V metodě subscribe() ověřujeme, zda jsou vstupní data validní. Pokud nejsou, Livewire automaticky zobrazí chybové hlášky v naší šabloně.

Nakonec tedy v souboru new-subscriber-form.blade.php vytvoříme naši šablonu pro formulář:

<div>
    <div class="items-top mb-3 space-y-4 sm:flex sm:space-y-0 max-w-4xl">
        <div class="relative w-full mr-1">
            <label for="newsletter_email" class="hidden mb-2 text-sm font-medium text-gray-900 dark:text-gray-300">
                {{ __('template.newsletter-email-label') }}
            </label>
            <div class="flex absolute inset-y-0 left-0 items-center pl-3 pointer-events-none">
                <svg class="w-5 h-5 text-gray-500 dark:text-gray-400" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2.003 5.884L10 9.882l7.997-3.998A2 2 0 0016 4H4a2 2 0 00-1.997 1.884z"></path><path d="M18 8.118l-8 4-8-4V14a2 2 0 002 2h12a2 2 0 002-2V8.118z"></path></svg>
            </div>
            <input wire:model.defer="email" class="block p-3 pl-10 w-full text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 sm:rounded-none sm:rounded-l-lg focus:ring-primary-500 focus:border-primary-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-white dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500" placeholder="{{ __('template.newsletter-email-placeholder') }}" type="email" id="newsletter_email">
            @error('email')
                <p class='mt-2 text-sm text-red-600'>{{ $message }}</p>
            @enderror
        </div>
        <div class="relative w-full md:w-80 mr-1">
            <label for="newsletter_language" class="hidden mb-2 text-sm font-medium text-gray-900 dark:text-gray-300">
                {{ __('template.newsletter-language-label') }}
            </label>
            <select wire:model.defer="language" id="newsletter_language" class="bg-gray-50 border border-gray-300 text-gray-900 rounded-lg text-sm focus:ring-blue-500 focus:border-blue-500 block w-full p-3 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
                @foreach (config('app.locales') as $lang => $language)
                    <option value="{{ $lang }}">{{ __('template.' . $lang) }}</option>
                @endforeach
            </select>
            @error('language')
                <p class='mt-2 text-sm text-red-600'>{{ $message }}</p>
            @enderror
        </div>
        <div>
            <button wire:click="subscribe()" wire:loading.attr="disabled" type="submit" class="py-3 px-5 w-full text-sm font-medium text-center text-white rounded-lg border cursor-pointer bg-primary-700 border-primary-600 sm:rounded-none sm:rounded-r-lg hover:bg-primary-800 focus:ring-4 focus:ring-primary-300 dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800">
                {{ __('template.newsletter-subscribe-button') }}
            </button>
        </div>
    </div>
</div>

Tento kód definuje formulář pro zadání emailu a výběr jazyka. Používáme zde příkaz wire:model, který nám umožňuje dvoucestnou databázovou vazbu mezi PHP a HTML. Také používáme wire:submit.prevent="subscribe" pro odeslání formuláře a zavolání naší metody subscribe().

A to je vše, co potřebujeme pro vytvoření naší Livewire komponenty. Jak na její integraci do stránky a další kroky se dozvíte níže.

Implementace Livewire komponenty do šablony

Použití Livewire komponenty ve vaší aplikaci Laravel je přímočaré a snadné. Ve vašem Blade šablonovacím souboru jednoduše použijete direktivu @livewire. Tato direktiva přijímá jako první parametr jméno Livewire komponenty, kterou chcete vložit, a jako druhý parametr můžete předat pole s daty, které chcete komponentě předat.

<section class="mb-4 md:mb-8">
    <div class="mx-auto">

        <h2 class="mb-2 text-xl tracking-tight font-extrabold text-gray-900 sm:text-2xl dark:text-white">
            {{ __('template.newsletter-headline') }}
        </h2>
        <p class="mx-auto mb-2 font-light text-gray-500 sm:text-xl dark:text-gray-400">
            {{ __('template.newsletter-description') }}
        </p>

        @livewire('guest.newsletter.new-subscriber-form', ['language' => app()->getLocale()])

    </div>
</section>

V příkladu guest.newsletter.new-subscriber-form je jméno naší komponenty a ['language' => app()->getLocale()] jsou data, která předáváme komponentě - konkrétně jazyk, na kterém se uživatel momentálně nachází. Díky tomuto jednoduchému zápisu můžeme komponentu snadno použít kdekoliv ve vašem projektu.

Nastavení trasování

Trasování (routing) je klíčovým prvkem jakékoliv webové aplikace. Laravel poskytuje skvělou podporu pro definování tras pro vaše aplikace.

V našem případě potřebujeme definovat pouze jednu trasu:

  • Trasa pro ověření emailové adresy uživatele.

Trasu definujeme v souboru routes/web.php.

...
Route::group([
    'prefix' => "{language}", 
    'where' => ['language' => '[a-zA-Z]{2}']
    ], function () {

    Route::get('/newsletter/verify/{token}', [NewsletterUserController::class, 'verify'])
        ->name('newsletter.verify-user')
        ->middleware('signed');

});
...

Poznámka: Bylo by možné použít 2 trasy - pro ověření emailové adresy uživatele a druhou trasu přímo pro Livewire komponentu. 

V našem případě využíváme tzv. signovanou trasu, která umožňuje vytvářet odkazy, které jsou bezpečné proti "padělání". Tato trasa vede k metodě verify v našem NewsletterVerificationController.

Překlady a internacionalizace

Laravel poskytuje mocný nástroj pro internacionalizaci vašich aplikací. Díky tomu můžete jednoduše vytvářet aplikace, které podporují více jazyků. Pro náš newsletter systém budeme potřebovat několik překladů.

Překlady v Laravelu jsou organizovány do souborů, které se nachází v adresáři resources/lang. Každý jazyk má svůj vlastní adresář a v něm jsou umístěny soubory s překlady.

V našem případě budeme potřebovat překlady pro dvě jazyky, češtinu a angličtinu. Vytvoříme tedy dva soubory:

  • resources/lang/cs/template.php
  • resources/lang/en/template.php

V těchto souborech definujeme překlady, které použijeme v našem systému pro přihlášení k odběru newsletteru. Každý soubor obsahuje pole, kde klíč představuje identifikátor překladu a hodnota je samotný překlad.

Ukázka pro český překlad:

<?php

return [
    ...
    'newsletter-headline' => "Přihlašte se k odběru novinek",
    'newsletter-description' => "Přihlaste se k odběru novinek o AI, Laravelu, SEO a mnoho dalšího.",
    'newsletter-email-label' => "Email",
    'newsletter-email-placeholder' => "Zadejte svůj email",
    'newsletter-language-label' => "Jazyk",
    'newsletter-subscribe-button' => "Odebírat",
    'newsletter-waiting-for-validation' => "Na váš e-mailový účet byl odeslán ověřovací odkaz.",
    'newsletter-invalid-token' => "Neplatný token.",
    'newsletter-successfuly-verified' => "Úspěšně ověřeno.",
    'newsletter-email-verification-subject' => "Ověřte prosím svou emailovou adresu",
    'newsletter-email-verification-headline' => "Vítejte v mém Newsletteru!",
    'newsletter-email-verification-description' => "Děkujeme, že jste se přihlásili k odběru mého newsletteru. Kliknutím na tlačítko níže ověřte svou e-mailovou adresu a dokončete odebírání novinek.",
    'newsletter-email-verification-verify-button' => "Ověřit email",
    'newsletter-email-verification-homepage-button' => "Přejít na web",
    'newsletter-email-verification-thanks' => "Děkuji",
    ...
];

Ukázka pro anglický překlad:

<?php

return [
    ...
    'newsletter-headline' => "Sign up for newsletter",
    'newsletter-description' => "Sign up for news on AI, Laravel, SEO and much more.",
    'newsletter-email-label' => "Email address",
    'newsletter-email-placeholder' => "Enter your email",
    'newsletter-language-label' => "Language",
    'newsletter-subscribe-button' => "Subscribe",
    'newsletter-waiting-for-validation' => "A verification link has been sent to your email account.",
    'newsletter-invalid-token' => "Invalid token.",
    'newsletter-successfuly-verified' => "Successfully verified.",
    'newsletter-email-verification-subject' => "Please verify your email address",
    'newsletter-email-verification-headline' => "Welcome to my Newsletter!",
    'newsletter-email-verification-description' => "Thank you for subscribing to my newsletter. Click the button below to verify your email address and complete your newsletter subscription.",
    'newsletter-email-verification-verify-button' => "Verify email",
    'newsletter-email-verification-homepage-button' => "Go to website",
    'newsletter-email-verification-thanks' => "Thanks",
    ...
];

Tyto překlady poté můžeme využít v našich šablonách nebo kódu pomocí helperu __ - jak již bylo ukázáno v předchozích částech kódu.

__('template.newsletter-email-verification-subject')

Tímto způsobem můžeme přidávat další jazyky do naší aplikace pouze přidáním dalších souborů s překlady. Laravel za nás automaticky vybere správný jazyk podle nastavení aplikace (což není obsahem tohoto článku).

Testování systému pomocí Pest

Když máme hotový systém pro přihlašování uživatelů k odběru newsletteru, je důležité se ujistit, že všechny jeho části fungují správně. K tomu slouží automatizované testy.

V Laravelu je pro testování populární nástroj Pest. Pest je elegantní wrapper nad PHPUnit, který umožňuje psát testy deklarativním stylem, který je často čitelnější a snazší na pochopení.

Pest umožňuje testovat všechny části naší aplikace. Můžeme testovat, zda se naše routy chovají správně, zda se data správně ukládají do databáze, nebo zda se odesílají správné e-maily.

Pro testování našeho newsletter systému vytvoříme dva testy:

  1. Test pro ověření uživatele newsletteru.
  2. Test pro odběr nových uživatelů pomocí Livewire komponenty.

V těchto testech ověříme, zda se uživatelé mohou přihlasit k newsletteru a ověřují, zda se odesílají ověřovací e-maily a zda se správně zobrazují flash zprávy.

Otestování Livewire komponenty - NewSubscriberFormTest.php:

<?php

use App\Enums\Newsletter\NewsletterLanguage;
use App\Http\Livewire\Guest\Newsletter\NewSubscriberForm;
use App\Mail\App\Guest\Newsletter\NewsletterVerificationMail;
use App\Models\Newsletter\NewsletterUser;
use Illuminate\Support\Facades\Mail;
use Livewire\Livewire;

it('subscribes a new user to the newsletter and sends a verification email', function () {
    Mail::fake();

    Livewire::test(NewSubscriberForm::class)
        ->set('email', 'test@example.com')
        ->set('language', NewsletterLanguage::ENGLISH->value)
        ->call('subscribe')
        ->assertDispatchedBrowserEvent('alert');

    expect(NewsletterUser::where('email', 'test@example.com')->first())
        ->email->toEqual('test@example.com')
        ->language->toEqual(NewsletterLanguage::ENGLISH)
        ->is_verified->toBeFalse();

    Mail::assertSent(NewsletterVerificationMail::class, function ($mail) {
        return $mail->newsletterUser->email === 'test@example.com' && 
            $mail->newsletterUser->language === NewsletterLanguage::ENGLISH;
    });
});

it('validates the new user subscription input data', function () {
    Livewire::test(NewSubscriberForm::class)
        ->set('email', 'invalid-email')
        ->set('language', 'invalid-language')
        ->call('subscribe')
        ->assertHasErrors(['email', 'language']);
});

Otestování řadiče - NewsletterUserControllerTest.php:

<?php

use App\Models\Newsletter\NewsletterUser;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\URL;

it('verifies a newsletter user successfully and redirects to the homepage with a success flash message', function () {
    $newsletterUser = NewsletterUser::factory()->create();

    $response = $this->get(URL::signedRoute('newsletter.verify-user', [
        'language' => $newsletterUser->language,
        'token' => $newsletterUser->verification_token
    ]));

    $response->assertStatus(302);
    $response->assertRedirect(route('homepage', ['language' => $newsletterUser->language]));
    $response->assertSessionHas('flashType', 'success');
    $response->assertSessionHas('flashMessage', __('template.newsletter-successfuly-verified'));

    $newsletterUser->refresh();
    expect($newsletterUser->is_verified)->toBeTrue();
});

it('fails to verify a newsletter user for an invalid token and redirects to the homepage with an error flash message', function () {
    $response = $this->get(URL::signedRoute('newsletter.verify-user', [
        'language' => Config::get('translatable.fallback_locale'),
        'token' => 'invalidtoken'
    ]));

    $response->assertStatus(302);
    $response->assertRedirect(route('homepage', ['language' => Config::get('translatable.fallback_locale')]));
    $response->assertSessionHas('flashType', 'error');
    $response->assertSessionHas('flashMessage', __('template.newsletter-invalid-token'));

    expect(NewsletterUser::where('is_verified', true)->count())->toBe(0);
});

Pro testování rout a HTTP odpovědí nám Pest poskytuje řadu metod pro přiřazování jako assertStatus, assertRedirect nebo například assertSessionHas. Pro ověření stavu v databázi můžeme využít metodu assertDatabaseHas.

Laravel Newsletter System - Testy

Při psaní testů je důležité myslet na to, aby testy pokrývaly všechny možné scénáře a aby byly nezávislé na sobě. To znamená, že každý test by měl mít svůj vlastní izolovaný stav a neměl by ovlivňovat výsledky ostatních testů.

Práce s akcemi

Akce v Laravelu nám pomáhají udržet náš kód organizovaný a zároveň zajistit, že každá operace je jednoznačně definována. V našem systému pro přihlášení k odběru newsletteru jsme vytvořili dvě klíčové akce - CreateNewsletterUserAction a VerifyNewsletterUserAction, které jsme ve článku nijak nerozebírali.

CreateNewsletterUserAction se stará o vytvoření nového uživatele v naší databázi newsletteru. Zde dochází k zápisu e-mailu a jazyka, který si uživatel vybral pro odběr novinek.

<?php

namespace App\Actions\Guest\Newsletter;

use App\Models\Newsletter\NewsletterUser;

class CreateNewsletterUserAction
{
    public function execute(array $validatedData): NewsletterUser
    {
        return NewsletterUser::create($validatedData);
    }
}

VerifyNewsletterUserAction poté ověřuje uživatele na základě tokenu, který obdržel v ověřovacím e-mailu. Tato akce také nastavuje příznak is_verified na true po úspěšném ověření.

<?php

namespace App\Actions\Guest\Newsletter;

use App\Models\Newsletter\NewsletterUser;

class VerifyNewsletterUserAction
{
    public function execute(NewsletterUser $newsletterUser): NewsletterUser
    {
        $newsletterUser->update([
            'is_verified' => true,
            'verification_token' => null
        ]);

        return $newsletterUser;
    }
}

Tyto dvě akce ukazují, jak můžeme efektivně organizovat naše operace v Laravelu. Usnadňují nám do budoucna škálovatelnost našeho systému pro newslettery.

Využití Enum pro jazykové nastavení

Enumerátor NewsletterLanguage nám poskytuje elegantní a bezpečný způsob, jak manipulovat s jazykovými kódy v naší aplikaci. Pomocí Enum máme jistotu, že budeme pracovat pouze s povolenými hodnotami - v našem případě en pro angličtinu a cs pro češtinu.

Použití Enum také zvyšuje čitelnost kódu a usnadňuje údržbu, jelikož všechny možné hodnoty jsou centralizovány na jednom místě.

<?php

namespace App\Enums\Newsletter;

use Illuminate\Support\Collection;

enum NewsletterLanguage: string
{
    case ENGLISH = 'en';
    case CZECH = 'cs';

    public static function all(): Collection
    {
        return collect(NewsletterLanguage::cases())->map(
            fn(NewsletterLanguage $code) => $code->details()
        );
    }

    public function details(): array
    {
        return match($this) 
        {
            self::ENGLISH => [
                'name'  => 'English',
                'value' => 'en',
            ],

            self::CZECH => [
                'name'  => 'Czech',
                'value' => 'cs',
            ],
        };
    }
}

Metody all a details pak umožňují snadno získat všechny dostupné jazyky a jejich podrobnosti, což je užitečné například při naplnění výběrového pole jazyků ve formuláři.

Domácí úkol

Ačkoliv se jedná o funkční kód, který je pro tento příklad plně dostačující, upravil jsem několik souborů, abyste si v rámci vývoje vyzkoušeli i nějakou tu praktickou část.

  • Využití enumerátoru v Livewire komponentě
    V šabloně u Livewire komponenty jsem pro výčet jazyků použil iteraci nad polem uvedeným v konfiguračním souboru, konkrétně v app.php - config('app.locales'). V produkci by však bylo ideálním použít enum.
    Nápověda: Pročpak máme v enumerátoru metodu all()? Nešla by využít?
  • Ošetření validačních zpráv
    Livewire komponenta není celá přeložena. Laravel nám pro chybové hlášky dokáže vypsat zprávy v angličtině, nikoliv však v češtině.
    Nápověda: Livewire má pěkne popsanou dokumentaci a s využitím dokumentace od Laravelu by měl být tento úkol snadno vyřešitelný.
  • Vytvoření seederu
    Pokud chcete mít naplněnou databázi náhodně generovanými daty a nechcete se spoléhat pouze na testy, určitě využijete seeder. To také usnadní dalším vývojářům pochopit Vaši aplikaci bez nutnosti vytvářet data ručně.
    Nápověda: Jelikož máme továrnu pro tvorbu instancí modelu včetně ukázky použití v testu, nemělo by Vám nic dělat problémy.
  • Odesílejte mail ve frontě
    Aby uživatel nečekal, než se funkce vykoná (odešle se email), můžete u emailu použít zpracování přes tzv fronty.
    Nápověda: Laravel má opět vše pěkně shrnuté v dokumentaci. Osobně doporučuji "implementovat" ( 🙂 ) v souboru pro logiku emailu využití front (aneb jediná třída, která není použita v naší ukázce, přesto ji soubor obsahuje - dokonce je přidána, pokud soubor generujete přes artisan příkaz).

Závěr

Vytvoření systému pro přihlášení k odběru newsletteru v Laravelu může vypadat jako složitá úloha. Tento článek by Vám měl ukázat, že to ale není tak složité, jak by se mohlo na první pohled zdát. Díky tomuto průvodci jste měli možnost seznámit se s celým procesem od základní přípravy přes implementaci jednotlivých částí až po testování.

Laravel je výkonný a flexibilní framework, který umožňuje vytvářet různé typy webových aplikací. Pomocí Livewire můžeme snadno vytvářet dynamické komponenty a díky Pestu můžeme efektivně testovat naši aplikaci a ujistit se, že vše funguje správně.

Důležité je také pamatovat na internacionalizaci a připravit naši aplikaci pro vícejazyčné uživatele. Laravel nabízí skvělé nástroje pro práci s překlady a lokalizací.

Doufám, že vám tento průvodce pomohl porozumět, jak v Laravelu vytvořit systém pro přihlášení k odběru newsletteru a že vás inspiroval k dalším projektům. Pamatujte, že nejdůležitější je praktická zkušenost, takže neváhejte a pusťte se do vlastního projektu!

Sdílet:
5 / 5
Celkem hlasů: 2
Zatím jste nehodnotili.
Pavel Zaněk

Full-stack programátor & SEO konzultant

Pavel Zaněk je zkušený full-stack vývojář s odborností v SEO a programování v Laravelu. Jeho dovednosti zahrnují optimalizaci webových stránek, implementaci efektivních strategií pro zvýšení návštěvnosti a zlepšení pozic ve vyhledávačích. Pavel je expert na Laravel a jeho související technologie, včetně Livewire, Vue.js, MariaDB, Redis, TailwindCSS/Bootstrap a mnoho dalšího. Kromě svých programovacích dovedností má také silné zázemí v řízení VPS, což mu umožňuje zvládnout složité výzvy na straně serveru. Pavel je vysoce motivovaný a oddaný profesionál, který je zavázán k dodávání výjimečných výsledků. Jeho cílem je pomáhat klientům dosáhnout úspěchu v online prostoru a dosáhnout svých cílů s pomocí nejlepších webových technologií a strategií pro optimalizaci pro vyhledávače.

Komentáře

Zatím nebyl přidán žádný komentář.

Přidat komentář

Doporučené články

Jak vytvořit RSS feed ve frameworku Laravel

Publikováno 10.08.2023 od Pavel Zaněk

Odhadovaná doba čtení: 16 minut

laravel

Průvodce vytvářením RSS feedu ve frameworku Laravel bez externích balíčků. Od základních principů až po pokročilé techniky. Ideální pro vývojáře hledající efektivní a bezpečné řešení.

Pokračovat ve čtení

Tato stránka používá cookies na vylepšení vašeho uživatelského zážitku. - Zásady Cookies