package Mojolicious::Plugin::DefaultHelpers;
use Mojo::Base 'Mojolicious::Plugin';
use Mojo::ByteStream;
use Mojo::Collection;
use Mojo::IOLoop;
use Mojo::Util qw(dumper sha1_sum steady_time);
sub register {
my ($self, $app) = @_;
# Controller alias helpers
for my $name (qw(app flash param stash session url_for validation)) {
$app->helper($name => sub { shift->$name(@_) });
}
# Stash key shortcuts (should not generate log messages)
for my $name (qw(extends layout title)) {
$app->helper(
$name => sub {
my $c = shift;
my $stash = $c->stash;
$stash->{$name} = shift if @_;
$c->stash(@_) if @_;
return $stash->{$name};
}
);
}
$app->helper($_ => $self->can("_$_"))
for qw(accepts content content_for csrf_token current_route delay),
qw(inactivity_timeout url_with);
$app->helper(b => sub { shift; Mojo::ByteStream->new(@_) });
$app->helper(c => sub { shift; Mojo::Collection->new(@_) });
$app->helper(config => sub { shift->app->config(@_) });
$app->helper(dumper => sub { shift; dumper(@_) });
$app->helper(include => sub { shift->render_to_string(@_) });
$app->helper(ua => sub { shift->app->ua });
}
sub _accepts {
my $c = shift;
return $c->app->renderer->accepts($c, @_);
}
sub _content {
my ($c, $name, $content) = @_;
$name ||= 'content';
# Set (first come)
my $hash = $c->stash->{'mojo.content'} ||= {};
$hash->{$name} //= ref $content eq 'CODE' ? $content->() : $content
if defined $content;
# Get
return Mojo::ByteStream->new($hash->{$name} // '');
}
sub _content_for {
my ($c, $name, $content) = @_;
return _content($c, $name) unless defined $content;
my $hash = $c->stash->{'mojo.content'} ||= {};
return $hash->{$name} .= ref $content eq 'CODE' ? $content->() : $content;
}
sub _csrf_token {
my $c = shift;
$c->session->{csrf_token}
||= sha1_sum($c->app->secrets->[0] . steady_time . rand 999);
}
sub _current_route {
return '' unless my $endpoint = shift->match->endpoint;
return $endpoint->name unless @_;
return $endpoint->name eq shift;
}
sub _delay {
my $self = shift;
my $tx = $self->render_later->tx;
my $delay = Mojo::IOLoop->delay(@_);
$delay->catch(sub { $self->render_exception(pop) and undef $tx })->wait;
}
sub _inactivity_timeout {
return unless my $stream = Mojo::IOLoop->stream(shift->tx->connection // '');
$stream->timeout(shift);
}
sub _url_with {
my $c = shift;
return $c->url_for(@_)->query($c->req->url->query->clone);
}
1;
=encoding utf8
=head1 NAME
Mojolicious::Plugin::DefaultHelpers - Default helpers plugin
=head1 SYNOPSIS
# Mojolicious
$self->plugin('DefaultHelpers');
# Mojolicious::Lite
plugin 'DefaultHelpers';
=head1 DESCRIPTION
L<Mojolicious::Plugin::DefaultHelpers> is a collection of renderer helpers for
L<Mojolicious>.
This is a core plugin, that means it is always enabled and its code a good
example for learning to build new plugins, you're welcome to fork it.
See L<Mojolicious::Plugins/"PLUGINS"> for a list of plugins that are available
by default.
=head1 HELPERS
L<Mojolicious::Plugin::DefaultHelpers> implements the following helpers.
=head2 accepts
my $formats = $c->accepts;
my $format = $c->accepts('html', 'json', 'txt');
Select best possible representation for resource from C<Accept> request
header, C<format> stash value or C<format> C<GET>/C<POST> parameter with
L<Mojolicious::Renderer/"accepts">, defaults to returning the first extension
if no preference could be detected.
# Check if JSON is acceptable
$c->render(json => {hello => 'world'}) if $c->accepts('json');
# Check if JSON was specifically requested
$c->render(json => {hello => 'world'}) if $c->accepts('', 'json');
# Unsupported representation
$c->render(data => '', status => 204)
unless my $format = $c->accepts('html', 'json');
# Detected representations to select from
my @formats = @{$c->accepts};
=head2 app
%= app->secrets->[0]
Alias for L<Mojolicious::Controller/"app">.
=head2 b
%= b('test 123')->b64_encode
Turn string into a L<Mojo::ByteStream> object.
=head2 c
%= c(qw(a b c))->shuffle->join
Turn list into a L<Mojo::Collection> object.
=head2 config
%= config 'something'
Alias for L<Mojo/"config">.
=head2 content
%= content foo => begin
test
% end
%= content bar => 'Hello World!'
%= content 'foo'
%= content 'bar'
%= content
Store partial rendered content in named buffer and retrieve it, defaults to
retrieving the named buffer C<content>, which is commonly used for the
renderers C<layout> and C<extends> features. Note that new content will be
ignored if the named buffer is already in use.
=head2 content_for
% content_for foo => begin
test
% end
%= content_for 'foo'
Append partial rendered content to named buffer and retrieve it. Note that
named buffers are shared with the L</"content"> helper.
% content_for message => begin
Hello
% end
% content_for message => begin
world!
% end
%= content_for 'message'
=head2 csrf_token
%= csrf_token
Get CSRF token from L</"session">, and generate one if none exists.
=head2 current_route
% if (current_route 'login') {
Welcome to Mojolicious!
% }
%= current_route
Check or get name of current route.
=head2 delay
$c->delay(sub {...}, sub {...});
Disable automatic rendering and use L<Mojo::IOLoop/"delay"> to manage
callbacks and control the flow of events, which can help you avoid deep nested
closures and memory leaks that often result from continuation-passing style.
Calls L<Mojolicious::Controller/"render_exception"> if an error occured in one
of the steps, breaking the chain.
# Longer version
$c->render_later;
my $delay = Mojo::IOLoop->delay(sub {...}, sub {...});
$delay->catch(sub { $c->render_exception(pop) })->wait;
=head2 dumper
%= dumper {some => 'data'}
Dump a Perl data structure with L<Mojo::Util/"dumper">.
=head2 extends
% extends 'blue';
% extends 'blue', title => 'Blue!';
Set C<extends> stash value, all additional pairs get merged into the
L</"stash">.
=head2 flash
%= flash 'foo'
Alias for L<Mojolicious::Controller/"flash">.
=head2 inactivity_timeout
$c->inactivity_timeout(3600);
Use L<Mojo::IOLoop/"stream"> to find the current connection and increase
timeout if possible.
# Longer version
Mojo::IOLoop->stream($c->tx->connection)->timeout(3600);
=head2 include
%= include 'menubar'
%= include 'menubar', format => 'txt'
Alias for C<Mojolicious::Controller/"render_to_string">.
=head2 layout
% layout 'green';
% layout 'green', title => 'Green!';
Set C<layout> stash value, all additional pairs get merged into the
L</"stash">.
=head2 param
%= param 'foo'
Alias for L<Mojolicious::Controller/"param">.
=head2 session
%= session 'foo'
Alias for L<Mojolicious::Controller/"session">.
=head2 stash
%= stash 'foo'
% stash foo => 'bar';
Alias for L<Mojolicious::Controller/"stash">.
%= stash('name') // 'Somebody'
=head2 title
% title 'Welcome!';
% title 'Welcome!', foo => 'bar';
%= title
Set C<title> stash value, all additional pairs get merged into the
L</"stash">.
=head2 ua
%= ua->get('mojolicio.us')->res->dom->at('title')->text
Alias for L<Mojo/"ua">.
=head2 url_for
%= url_for 'named', controller => 'bar', action => 'baz'
Alias for L<Mojolicious::Controller/"url_for">.
=head2 url_with
%= url_with 'named', controller => 'bar', action => 'baz'
Does the same as L</"url_for">, but inherits query parameters from the current
request.
%= url_with->query([page => 2])
=head2 validation
%= validation->param('foo')
Alias for L<Mojolicious::Controller/"validation">.
=head1 METHODS
L<Mojolicious::Plugin::DefaultHelpers> inherits all methods from
L<Mojolicious::Plugin> and implements the following new ones.
=head2 register
$plugin->register(Mojolicious->new);
Register helpers in L<Mojolicious> application.
=head1 SEE ALSO
L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicio.us>.
=cut