Voyti
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()}");
}
],
];