---
title: "Perzistencia — Onboarding for Laravel | Roundly"
description: "Skryteľné voliteľné kroky a žiadne opakované ohlásenia uložených dokončení — stačí cez Onboarding::useStore() zapojiť vlastný OnboardingStore."
url: https://roundly-consulting.com/sk/open-source/navody/onboarding-for-laravel/perzistencia
language: sk
---

[Všetky balíky](https://roundly-consulting.com/sk/open-source.md)

[Onboarding for Laravel](https://roundly-consulting.com/sk/open-source/navody/onboarding-for-laravel.md)

# Perzistencia

Balík je predvolene bezstavový, no využije OnboardingStore (RoundlyConsulting\\Onboarding\\Contracts\\OnboardingStore), ktorý mu poskytne aplikácia. Neprináša žiadnu tabuľku, model ani migráciu a bez store nerobí nič. Úložisko patrí vašej aplikácii: dokončenia (zvyčajne cez listener na StepCompleted) aj skrytia krokov, ktoré balík odovzdá do markDismissed().

```php
namespace RoundlyConsulting\Onboarding\Contracts;

interface OnboardingStore
{
    public function isDismissed(Authenticatable|Model|null $subject, string $stepKey): bool;

    public function completedAt(Authenticatable|Model|null $subject, string $stepKey): ?DateTimeInterface;

    public function markDismissed(Authenticatable|Model|null $subject, string $stepKey): void;
}
```

## Čo store umožní

- Skryteľné voliteľné kroky — voliteľný krok s dismissible(), ktorý subjekt skryl, zmizne zo steps() aj z percent. Povinné kroky sa skryť nedajú.
- Potlačené opakované ohlásenia — record() preskočí každý krok, ktorého completedAt() nie je null, takže keď listener dokončenie uloží, ďalšie požiadavky tento krok už neohlásia. Ide o čítanie, nie atomickú rezerváciu, preto majte listenery idempotentné — pozrite si Udalosti.

## Implementácia store

Kontrakt môžete oprieť o ľubovoľné úložisko. Tento príklad používa tabuľku, ktorú vlastní vaša aplikácia:

```php
namespace App\Onboarding;

use DateTimeInterface;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use RoundlyConsulting\Onboarding\Contracts\OnboardingStore;

// Your own table — the package ships none.
final class DatabaseOnboardingStore implements OnboardingStore
{
    public function isDismissed(Authenticatable|Model|null $subject, string $stepKey): bool
    {
        return $this->row($subject, $stepKey)?->dismissed_at !== null;
    }

    public function completedAt(Authenticatable|Model|null $subject, string $stepKey): ?DateTimeInterface
    {
        $at = $this->row($subject, $stepKey)?->completed_at;

        return $at === null ? null : Carbon::parse($at);
    }

    // Called by the manager when the subject dismisses an optional, dismissible step.
    public function markDismissed(Authenticatable|Model|null $subject, string $stepKey): void
    {
        if ($subject === null) {
            return;
        }

        DB::table('onboarding_steps')->updateOrInsert(
            ['user_id' => $subject->getKey(), 'step' => $stepKey],
            ['dismissed_at' => now()],
        );
    }

    private function row(Authenticatable|Model|null $subject, string $stepKey): ?object
    {
        if ($subject === null) {
            return null;
        }

        return DB::table('onboarding_steps')
            ->where('user_id', $subject->getKey())
            ->where('step', $stepKey)
            ->first();
    }
}
```

## Zapojenie

Store odovzdajte do Onboarding::useStore() — triedu vytvorí kontajner pri prvom použití a trieda, ktorá kontrakt neimplementuje, vyhodí InvalidStoreException:

```php
// app/Providers/AppServiceProvider.php — boot()
use App\Onboarding\DatabaseOnboardingStore;
use RoundlyConsulting\Onboarding\Facades\Onboarding;

Onboarding::useStore(DatabaseOnboardingStore::class);   // resolved through the container on first use
Onboarding::useStore(new DatabaseOnboardingStore);      // or an instance

Onboarding::hasStore();   // true
Onboarding::store();      // ?OnboardingStore — the store in use
```

Bez useStore() sa použije store naviazaný v kontajneri:

```php
// the fallback when useStore() was never called — app/Providers/AppServiceProvider.php, register()
use App\Onboarding\DatabaseOnboardingStore;
use RoundlyConsulting\Onboarding\Contracts\OnboardingStore;

$this->app->bind(OnboardingStore::class, DatabaseOnboardingStore::class);
```

## Ukladanie dokončení

Počúvajte StepCompleted a zapíšte čas dokončenia — ďalšie record() potom tento krok preskočí:

```php
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Event;
use RoundlyConsulting\Onboarding\Events\StepCompleted;

Event::listen(StepCompleted::class, function (StepCompleted $e): void {
    if ($e->for === null) {
        return;
    }

    DB::table('onboarding_steps')->updateOrInsert(
        ['user_id' => $e->for->getKey(), 'step' => $e->step->stepKey()],
        ['completed_at' => now()],
    );
});
```

## Skrytie kroku

```php
$flow = Onboarding::flow('default')->title('Profile Onboarding');

$flow->add('Add a bio')->key('add-bio')->optional()->dismissible()
    ->completeWhenFilled('bio');

// e.g. from a "Not now" button — all three go through the manager to markDismissed()
Onboarding::for($user)?->dismiss('add-bio');   // returns the Flow
$user->dismissOnboardingStep('add-bio');       // the trait shorthand
$user->onboarding()?->dismiss('add-bio');
```

Každé skrytie ide cez manager, ktorý zavolá markDismissed() v store. Pôsobí len na viditeľný voliteľný krok označený dismissible() a bez store, pri neznámom, povinnom či neskryteľnom kroku nerobí nič — do store sa nič nezapíše.

FlowCompleted sa nepotláča — record() ju odošle vždy, keď je tok dokončený, a record($key) vždy, keď ohlásil daný povinný krok. Listener, ktorý má „oslavovať“ len raz, preto navrhnite idempotentne.

## Kľúče krokov platia naprieč tokmi

Store aj udalosti identifikujú krok len podľa subjektu a kľúča kroku — kľúč toku v tom nehrá rolu. Dokončenie či skrytie verify-email v jednom toku platí v každom toku, ktorý má krok verify-email, čo pri zdieľaných krokoch zvyčajne chcete. Pre stav, ktorý patrí len jednému toku, dajte kroku kľúč špecifický pre tok, napríklad s prefixom:

```php
Onboarding::flow('vendor')->addStep(Step::make('Add a bio')->key('vendor.add-bio')->optional()->dismissible());
```

## Prejavte lásku k open source

Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.

[Ďalšie spôsoby podpory vrátane kryptomien](https://roundly-consulting.com/sk/podporte-nas.md)

Odoslaním daru súhlasíte s našimi [podmienkami prijímania darov](https://roundly-consulting.com/sk/podmienky-darov.md).

[Podporte našu open-source prácu (otvorí sa v novej karte)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Pridajte sa k nám na Patreone (otvorí sa v novej karte)](https://www.patreon.com/cw/roundly)

## Chcete to zabudovať do svojho produktu?

Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.

[Ponuka do 48 hodín](https://roundly-consulting.com/sk/kontakt.md) [Prezrieť všetky balíky](https://roundly-consulting.com/sk/open-source/navody/onboarding-for-laravel.md)
