Voyti

Voyti

User management, authentication & authorization

Cookbook

Building a nav menu from Voyti's routes

Voyti does not provide a menu model or navigation contract, it only exposes named routes that the host application wires into its own menu, sidebar, or access rules. For example, a yiisoft/yii-bootstrap5 nav built from those routes might look like:

use Yiisoft\Yii\Bootstrap5\Nav;
use Yiisoft\Yii\Bootstrap5\NavLink;

echo Nav::widget()->items(
    NavLink::to($this->translator->translate('voyti.view.login.title', category: 'voyti'), $this->url->generate('voyti/session-login'))
        ->visible($this->currentUser->isGuest()),
    NavLink::to('User', $this->url->generate('voyti/user'))
        ->active(str_starts_with($this->currentRoute->getName() ?? '', 'voyti/user'))
        ->visible(!$this->currentUser->isGuest()),
    NavLink::to('Admin', $this->url->generate('voyti/admin'))
        ->active(str_starts_with($this->currentRoute->getName() ?? '', 'voyti/admin'))
        ->visible($this->authHelper->isAdmin()),
);

voyti/session-logout only accepts POST, so it can’t be a plain NavLink. Render it as its own small form instead, styled to match the nav:

use Yiisoft\Html\Html;

if (!$this->currentUser->isGuest()) {
    echo Html::li()->class('nav-item')->open();
    echo Html::form()->post($this->url->generate('voyti/session-logout'))->csrf($csrf)->open();
    echo Html::submitButton($this->translator->translate('voyti.menu.logout', category: 'voyti'))
        ->class('nav-link', 'btn', 'btn-link');
    echo Html::form()->close();
    echo Html::li()->close();
}

$csrf here is the Csrf value object that Yiisoft\Yii\View\Renderer\CsrfViewInjection makes available to views when it’s registered as a common parameter injection.

Styling required field indicators with CSS

First, enable enrichFromValidationRules in your field theme config (see Quick Start) so that validation rules are translated to HTML5 attributes like required. Then add this to your stylesheet:

div:has([required]) > label::after {
    content: '\a0*';
    color: red;
}

Rendering flash messages as Bootstrap toasts

Voyti reports action outcomes - login, logout, password recovery, a saved profile - as session flash messages, and its own pages render them for you: as Bootstrap 5 toasts when the optional toast-bootstrap5 package is installed, or plain alerts otherwise. To surface them on your own pages too - such as the home page, where voyti/session-logout redirects after logout - render the toast container in your layout:

<?= $toast->render($this) ?>

Showing the impersonation banner in your own layout

When an admin uses voyti/admin-users-switch-identity to temporarily assume another user’s identity, drop in YiiRocks\Voyti\Widget\SwitchIdentity anywhere in your layout to show the “you’re logged in as this user” banner with a restore button:

if (!str_starts_with($this->currentRoute->getName() ?? '', 'voyti/')) {
    echo YiiRocks\Voyti\Widget\SwitchIdentity::widget();
}

Its dependencies resolve through the DI container, so this needs no wiring beyond having Voyti installed, and it renders an empty string when nobody is impersonating anyone.

Attaching a listener to a Voyti event

Attach listeners through the Yii3 event dispatcher configuration:

For events with discriminator types like UserEvent, check the type to handle specific actions. You can attach multiple listeners to the same event, and each receives the event object plus any other DI dependencies.

// config/events.php or config/events-web.php
use Psr\Log\LoggerInterface;
use YiiRocks\Voyti\Event\User\UserProfileEvent;
use YiiRocks\Voyti\Event\User\UserEvent;

return [
    UserEvent::class => [
        static function(UserEvent $event, LoggerInterface $logger) {
            if ($event->getType() === UserEvent::BLOCK) {
                $user = $event->getUser();
                $logger->warning("User blocked: {$user->getUsername()}");
            }
        }
    ],
    UserProfileEvent::class => [
        static function(UserProfileEvent $event, LoggerInterface $logger) {
            $user = $event->getUser();
            $logger->info("User profile updated: {$user->getUsername()}");
        }
    ],
];