Mojolicious-Plugin-Fondation-Menu
view release on metacpan or search on metacpan
lib/Mojolicious/Plugin/Fondation/Menu/Helpers.pm view on Meta::CPAN
package Mojolicious::Plugin::Fondation::Menu::Helpers;
$Mojolicious::Plugin::Fondation::Menu::Helpers::VERSION = '0.04';
# ABSTRACT: Menu helpers â server-side cache, rendering, breadcrumb
use strict;
use warnings;
use Mojo::Base -strict, -signatures;
# ââ Register all helpers ââââââââââââââââââââââââââââââââââââââââââââââââ
sub register_all ($class, $app) {
# ââ _menus_cache ââââââââââââââââââââââââââââââââââââââââââââââââââ
# Returns the server-side cache hashref (lazy, shared across users)
my $_menus_cache;
my $_menus_loaded = 0;
my $_get_cache = sub {
return $_menus_cache if $_menus_loaded;
return undef;
};
my $_invalidate_cache = sub {
$_menus_loaded = 0;
undef $_menus_cache;
};
my $_ensure_cache;
# ââ breadcrumb âââââââââââââââââââââââââââââââââââââââââââââââââââââ
$app->helper(breadcrumb => sub ($c) {
$_ensure_cache->($c);
my $menus = $_get_cache->();
return [] unless $menus && $menus->{_by_path};
my $path = $c->req->url->path->to_abs_string // '/';
$path = "/$path" unless $path =~ m|^/|;
return [] if $path eq '/';
my $menu = $menus->{_by_path}{$path};
unless ($menu) {
$menu = _find_menu_by_path_prefix($path, $menus->{_by_path});
}
return [] unless $menu;
my @trail = ($menu);
while ($menu->{parent_id}) {
$menu = $menus->{_by_id}{$menu->{parent_id}};
last unless $menu;
unshift @trail, $menu;
}
return \@trail;
});
# ââ menu_by_name ââââââââââââââââââââââââââââââââââââââââââââââââââââ
$app->helper(menu_by_name => sub ($c, $name) {
$_ensure_cache->($c);
my $menus = $_get_cache->();
return [] unless $menus && $menus->{_by_name};
return $menus->{_by_name}{$name} // [];
});
# ââ menu_by_id ââââââââââââââââââââââââââââââââââââââââââââââââââââââ
$app->helper(menu_by_id => sub ($c, $id) {
my $menus = $_get_cache->();
return undef unless $menus && $menus->{_by_id};
return $menus->{_by_id}{$id};
});
# ââ menus âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
$app->helper(menus => sub ($c, $init = undef) {
my $cache = $_get_cache->();
return $cache if $cache && !$init;
return _build_menus_cache($c, \$_menus_cache, \$_menus_loaded);
});
# ââ render_menu ââââââââââââââââââââââââââââââââââââââââââââââ
$app->helper(render_menu => sub ($c, $name) {
my $menus = $c->menu_by_name($name);
return '' unless @$menus;
return $c->render_to_string(
template => 'menu/navbar',
menus => $menus,
);
});
# ââ check_menu_condition ââââââââââââââââââââââââââââââââââââââââââââ
$app->helper(check_menu_condition => sub ($c, $condition) {
return 1 unless defined $condition && length $condition;
# Support comma-separated compound conditions (AND logic)
for my $cond (split /\s*,\s*/, $condition) {
return 0 unless _check_single_menu_condition($c, $cond);
}
return 1;
});
# ââ render_menu_breadcrumb ââââââââââââââââââââââââââââââââââââââââââ
$app->helper(render_menu_breadcrumb => sub ($c) {
my $trail = $c->breadcrumb;
return '' unless @$trail;
return $c->render_to_string(
template => 'menu/breadcrumb',
trail => $trail,
);
});
# ââ menu_cache_invalidate âââââââââââââââââââââââââââââââââââââââââââ
# Called by CRUD operations to clear the cache.
$app->helper(menu_cache_invalidate => sub { $_invalidate_cache->() });
# ââ _ensure_cache âââââââââââââââââââââââââââââââââââââââââââââââââââ
# Lazy-init cache on first access (non-blocking, no hook needed).
$_ensure_cache = sub ($c) {
return if $_menus_loaded;
_build_menus_cache($c, \$_menus_cache, \$_menus_loaded);
};
}
# ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
# Internal
# ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
# Check a single menu condition (no comma splitting).
sub _check_single_menu_condition ($c, $cond) {
if ($cond eq 'auth') {
return $c->has_helper('is_user_authenticated')
? $c->is_user_authenticated : 0;
}
if ($cond eq '!auth') {
return $c->has_helper('is_user_authenticated')
? !$c->is_user_authenticated : 1;
}
if ($cond =~ /^group:(.+)$/) {
return $c->check_group($1);
}
if ($cond =~ /^perm:(.+)$/) {
return $c->check_perm($1);
}
if ($cond =~ /^mode:!(.+)$/) {
return $c->app->mode ne $1;
}
if ($cond =~ /^mode:(.+)$/) {
return $c->app->mode eq $1;
}
$c->app->log->warn("Unknown menu condition format: $cond");
return 0;
}
sub _build_menus_cache ($c, $cache_ref, $loaded_ref) {
my $schema = $c->schema;
return undef unless $schema;
my $results = $schema->await(
$schema->resultset('Menu')->search(
undef,
{ order_by => { -asc => 'sort_order' } },
)->all
);
my @plain;
for my $m (@$results) {
push @plain, {
id => $m->id,
title => $m->title,
link => $m->link,
icon => $m->icon,
icon_color => $m->icon_color,
name => $m->name,
condition => $m->condition,
( run in 0.638 second using v1.01-cache-2.11-cpan-ad19def0cd9 )