Below is an example Mojolicious (6.14) app... Sorry for the $_[0] and other less-than-best practices; I tried to make it compact.
package ScopeTest;
use Mojo::Base 'Mojolicious';
sub startup {
my $app = shift;
$app->helper( hello => sub { "Hello!" } );
$app->helper( username => sub { $_[0]->session('username'); } );
$app->helper( model => sub { ScopeTest::Model->new( app => $_[0]->app ) } );
$app->helper( hasPerm => sub { $_[0]->model->hasPerm( @_ ) } );
$app->routes->get('/alice')->to('controller#alice');
$app->routes->get('/carol')->to('controller#carol');
$app->routes->get('/steve')->to('controller#steve');
}
##############################
package ScopeTest::Controller;
use Mojo::Base 'Mojolicious::Controller';
sub alice { $_[0]->session( username => "alice" ); $_[0]->render_message() }
sub carol { $_[0]->session( username => "carol" ); $_[0]->render_message() }
sub steve { $_[0]->session( username => "steve" ); $_[0]->render( text =>
sprintf "%s: %s\n", $_[0]->username, $_[0]->model->update_db ? 'Okay' : 'Fail' ) }
sub render_message { $_[0]->render( text =>
sprintf "%s: %s\n", $_[0]->username, $_[0]->hasPerm('canLogin') ? 'Okay' : 'Fail' ) }
##############################
package ScopeTest::Model;
use Mojo::Base -base;
has 'app';
my %perms = ( alice => [ qw{ canLogin } ],
carol => [ ],
steve => [ qw{ canUpdateDB } ] );
sub hasPerm {
my ( $self, $perm ) = @_;
no warnings 'uninitialized';
$self->app->log->debug("app->hello = " . $self->app->hello ); # OKAY
$self->app->log->debug("app->username = " . $self->app->username ); # FAILS
$self->app->log->debug("session('username') = " . $self->app->session('username') ); # FAILS
$self->app->log->debug("session->{'username'} = " . $self->app->session->{'username'} ); # FAILS
my $username; # = $self->app->username;
return grep { $_ eq $perm } @{ $perms{$username} };
}
sub update_db {
my ( $self, $data ) = @_;
$self->hasPerm('canUpdateDB') or return;
# else ...
return 1;
}
1;
Although things like $self->app->log->debug()
and $self->app->dumper()
and other helpers do the right thing, $self->app->session
does not.
I know passing in $app
is considered less-than-ideal, but I would have expected the above to at least WORK...
Short of passing the username around over and over (this is a toy example; the real app has dozens of different methods which sometimes call each other, etc.) is there a cleaner way to access session data from within a model class?
PS — And before you say, Model->new(username => $self->session('username')
, that means knowing, a priori, what session variables I'm going to need, and enumerating them all in the constructor and attribute lists; I was hoping that if I just passed in the whole $app
(or even $app->session
), I could keep things future-proof.
Thanks!
The mistake I was making was: "session" info isn't associated with the App; it's associated with the Controller:
$app->helper( model => sub { ScopeTest::Model->new( ctrl => $_[0] ) } );
then:
package ScopeTest::Model;
use Mojo::Base -base;
has 'ctrl';
...
$self->ctrl->app->log->debug("username = " . $self->ctrl->username );
Yeah, I know it's still sub-optimal to pass the Controller to the Model, but this at least explains why I couldn't get it to work at ALL before...