1201 lines
28 KiB
Perl
1201 lines
28 KiB
Perl
package Mojolicious;
|
||
use Mojo::Base -base;
|
||
|
||
# "Fry: Shut up and take my money!"
|
||
use Carp ();
|
||
use Mojo::DynamicMethods -dispatch;
|
||
use Mojo::Exception;
|
||
use Mojo::Home;
|
||
use Mojo::Log;
|
||
use Mojo::Util;
|
||
use Mojo::UserAgent;
|
||
use Mojolicious::Commands;
|
||
use Mojolicious::Controller;
|
||
use Mojolicious::Plugins;
|
||
use Mojolicious::Renderer;
|
||
use Mojolicious::Routes;
|
||
use Mojolicious::Sessions;
|
||
use Mojolicious::Static;
|
||
use Mojolicious::Types;
|
||
use Mojolicious::Validator;
|
||
use Scalar::Util ();
|
||
|
||
has commands => sub { Mojolicious::Commands->new(app => shift) };
|
||
has controller_class => 'Mojolicious::Controller';
|
||
has home => sub { Mojo::Home->new->detect(ref shift) };
|
||
has log => sub {
|
||
my $self = shift;
|
||
|
||
# Check if we have a log directory that is writable
|
||
my $log = Mojo::Log->new;
|
||
my $home = $self->home;
|
||
my $mode = $self->mode;
|
||
$log->path($home->child('log', "$mode.log")) if -d $home->child('log') && -w _;
|
||
|
||
# Reduced log output outside of development mode
|
||
return $log->level($ENV{MOJO_LOG_LEVEL}) if $ENV{MOJO_LOG_LEVEL};
|
||
return $mode eq 'development' ? $log : $log->level('info');
|
||
};
|
||
has 'max_request_size';
|
||
has mode => sub { $ENV{MOJO_MODE} || $ENV{PLACK_ENV} || 'development' };
|
||
has moniker => sub { Mojo::Util::decamelize ref shift };
|
||
has plugins => sub { Mojolicious::Plugins->new };
|
||
has renderer => sub { Mojolicious::Renderer->new };
|
||
has routes => sub { Mojolicious::Routes->new };
|
||
has secrets => sub {
|
||
my $self = shift;
|
||
|
||
# Warn developers about insecure default
|
||
$self->log->debug('Your secret passphrase needs to be changed');
|
||
|
||
# Default to moniker
|
||
return [$self->moniker];
|
||
};
|
||
has sessions => sub { Mojolicious::Sessions->new };
|
||
has static => sub { Mojolicious::Static->new };
|
||
has types => sub { Mojolicious::Types->new };
|
||
has ua => sub { Mojo::UserAgent->new };
|
||
has validator => sub { Mojolicious::Validator->new };
|
||
|
||
our $CODENAME = 'Supervillain';
|
||
our $VERSION = '8.57';
|
||
|
||
sub BUILD_DYNAMIC {
|
||
my ($class, $method, $dyn_methods) = @_;
|
||
|
||
return sub {
|
||
my $self = shift;
|
||
my $dynamic = $dyn_methods->{$self->renderer}{$method};
|
||
return $self->build_controller->$dynamic(@_) if $dynamic;
|
||
my $package = ref $self;
|
||
Carp::croak qq{Can't locate object method "$method" via package "$package"};
|
||
};
|
||
}
|
||
|
||
sub build_controller {
|
||
my ($self, $tx) = @_;
|
||
|
||
# Embedded application
|
||
my $stash = {};
|
||
if ($tx && (my $sub = $tx->can('stash'))) { ($stash, $tx) = ($tx->$sub, $tx->tx) }
|
||
|
||
# Build default controller
|
||
my $defaults = $self->defaults;
|
||
@$stash{keys %$defaults} = values %$defaults;
|
||
my $c = $self->controller_class->new(app => $self, stash => $stash, tx => $tx);
|
||
$c->{tx} ||= $self->build_tx;
|
||
|
||
return $c;
|
||
}
|
||
|
||
sub build_tx {
|
||
my $self = shift;
|
||
|
||
my $tx = Mojo::Transaction::HTTP->new;
|
||
my $max = $self->max_request_size;
|
||
$tx->req->max_message_size($max) if defined $max;
|
||
$self->plugins->emit_hook(after_build_tx => $tx, $self);
|
||
|
||
return $tx;
|
||
}
|
||
|
||
sub config { Mojo::Util::_stash(config => @_) }
|
||
sub defaults { Mojo::Util::_stash(defaults => @_) }
|
||
|
||
sub dispatch {
|
||
my ($self, $c) = @_;
|
||
|
||
my $plugins = $self->plugins->emit_hook(before_dispatch => $c);
|
||
|
||
# Try to find a static file
|
||
my $tx = $c->tx;
|
||
$self->static->dispatch($c) and $plugins->emit_hook(after_static => $c) unless $tx->res->code;
|
||
|
||
# Start timer (ignore static files)
|
||
my $stash = $c->stash;
|
||
$c->helpers->log->debug(sub {
|
||
my $req = $c->req;
|
||
my $method = $req->method;
|
||
my $path = $req->url->path->to_abs_string;
|
||
$c->helpers->timing->begin('mojo.timer');
|
||
return qq{$method "$path"};
|
||
}) unless $stash->{'mojo.static'};
|
||
|
||
# Routes
|
||
$plugins->emit_hook(before_routes => $c);
|
||
$c->helpers->reply->not_found
|
||
unless $tx->res->code || $self->routes->dispatch($c) || $tx->res->code || $c->stash->{'mojo.rendered'};
|
||
}
|
||
|
||
sub handler {
|
||
my $self = shift;
|
||
|
||
# Dispatcher has to be last in the chain
|
||
++$self->{dispatch}
|
||
and $self->hook(around_action => \&_action)
|
||
and $self->hook(around_dispatch => sub { $_[1]->app->dispatch($_[1]) })
|
||
unless $self->{dispatch};
|
||
|
||
# Process with chain
|
||
my $c = $self->build_controller(@_);
|
||
$self->plugins->emit_chain(around_dispatch => $c);
|
||
|
||
# Delayed response
|
||
$c->helpers->log->debug('Nothing has been rendered, expecting delayed response') unless $c->stash->{'mojo.rendered'};
|
||
}
|
||
|
||
sub helper { shift->renderer->add_helper(@_) }
|
||
|
||
sub hook { shift->plugins->on(@_) }
|
||
|
||
sub new {
|
||
my $self = shift->SUPER::new(@_);
|
||
|
||
my $home = $self->home;
|
||
push @{$self->renderer->paths}, $home->child('templates')->to_string;
|
||
push @{$self->static->paths}, $home->child('public')->to_string;
|
||
|
||
# Default to controller and application namespace
|
||
my $r = $self->routes->namespaces(["@{[ref $self]}::Controller", ref $self]);
|
||
|
||
# Hide controller attributes/methods
|
||
$r->hide(qw(app continue cookie every_cookie every_param every_signed_cookie finish helpers match on param render));
|
||
$r->hide(qw(render_later render_maybe render_to_string rendered req res send session signed_cookie stash tx url_for));
|
||
$r->hide(qw(write write_chunk));
|
||
|
||
$self->plugin($_) for qw(HeaderCondition DefaultHelpers TagHelpers EPLRenderer EPRenderer);
|
||
|
||
# Exception handling should be first in chain
|
||
$self->hook(around_dispatch => \&_exception);
|
||
|
||
$self->startup;
|
||
|
||
return $self;
|
||
}
|
||
|
||
sub plugin {
|
||
my $self = shift;
|
||
$self->plugins->register_plugin(shift, $self, @_);
|
||
}
|
||
|
||
sub server { $_[0]->plugins->emit_hook(before_server_start => @_[1, 0]) }
|
||
|
||
sub start {
|
||
my $self = shift;
|
||
$_->warmup for $self->static, $self->renderer;
|
||
return $self->commands->run(@_ ? @_ : @ARGV);
|
||
}
|
||
|
||
sub startup { }
|
||
|
||
sub _action {
|
||
my ($next, $c, $action, $last) = @_;
|
||
my $val = $action->($c);
|
||
$val->catch(sub { $c->helpers->reply->exception(shift) }) if Scalar::Util::blessed $val && $val->isa('Mojo::Promise');
|
||
return $val;
|
||
}
|
||
|
||
sub _die { CORE::die ref $_[0] ? $_[0] : Mojo::Exception->new(shift)->trace }
|
||
|
||
sub _exception {
|
||
my ($next, $c) = @_;
|
||
local $SIG{__DIE__} = \&_die;
|
||
$c->helpers->reply->exception($@) unless eval { $next->(); 1 };
|
||
}
|
||
|
||
1;
|
||
|
||
=encoding utf8
|
||
|
||
=head1 NAME
|
||
|
||
Mojolicious - Real-time web framework
|
||
|
||
=head1 SYNOPSIS
|
||
|
||
# Application
|
||
package MyApp;
|
||
use Mojo::Base 'Mojolicious';
|
||
|
||
# Route
|
||
sub startup {
|
||
my $self = shift;
|
||
$self->routes->get('/hello')->to('foo#hello');
|
||
}
|
||
|
||
# Controller
|
||
package MyApp::Controller::Foo;
|
||
use Mojo::Base 'Mojolicious::Controller';
|
||
|
||
# Action
|
||
sub hello {
|
||
my $self = shift;
|
||
$self->render(text => 'Hello World!');
|
||
}
|
||
|
||
=head1 DESCRIPTION
|
||
|
||
An amazing real-time web framework built on top of the powerful L<Mojo> web development toolkit. With support for
|
||
RESTful routes, plugins, commands, Perl-ish templates, content negotiation, session management, form validation,
|
||
testing framework, static file server, C<CGI>/C<PSGI> detection, first class Unicode support and much more for you to
|
||
discover.
|
||
|
||
Take a look at our excellent documentation in L<Mojolicious::Guides>!
|
||
|
||
=head1 HOOKS
|
||
|
||
L<Mojolicious> will emit the following hooks in the listed order.
|
||
|
||
=head2 before_command
|
||
|
||
Emitted right before the application runs a command through the command line interface. Note that this hook is
|
||
B<EXPERIMENTAL> and might change without warning!
|
||
|
||
$app->hook(before_command => sub {
|
||
my ($command, $args) = @_;
|
||
...
|
||
});
|
||
|
||
Useful for reconfiguring the application before running a command or to modify the behavior of a command. (Passed the
|
||
command object and the command arguments)
|
||
|
||
=head2 before_server_start
|
||
|
||
Emitted right before the application server is started, for web servers that support it, which includes all the
|
||
built-in ones (except for L<Mojo::Server::CGI>).
|
||
|
||
$app->hook(before_server_start => sub {
|
||
my ($server, $app) = @_;
|
||
...
|
||
});
|
||
|
||
Useful for reconfiguring application servers dynamically or collecting server diagnostics information. (Passed the
|
||
server and application objects)
|
||
|
||
=head2 after_build_tx
|
||
|
||
Emitted right after the transaction is built and before the HTTP request gets parsed.
|
||
|
||
$app->hook(after_build_tx => sub {
|
||
my ($tx, $app) = @_;
|
||
...
|
||
});
|
||
|
||
This is a very powerful hook and should not be used lightly, it makes some rather advanced features such as upload
|
||
progress bars possible. Note that this hook will not work for embedded applications, because only the host application
|
||
gets to build transactions. (Passed the transaction and application objects)
|
||
|
||
=head2 around_dispatch
|
||
|
||
Emitted right after a new request has been received and wraps around the whole dispatch process, so you have to
|
||
manually forward to the next hook if you want to continue the chain. Default exception handling with
|
||
L<Mojolicious::Plugin::DefaultHelpers/"reply-E<gt>exception"> is the first hook in the chain and a call to
|
||
L</"dispatch"> the last, yours will be in between.
|
||
|
||
$app->hook(around_dispatch => sub {
|
||
my ($next, $c) = @_;
|
||
...
|
||
$next->();
|
||
...
|
||
});
|
||
|
||
This is a very powerful hook and should not be used lightly, it allows you to, for example, customize application-wide
|
||
exception handling, consider it the sledgehammer in your toolbox. (Passed a callback leading to the next hook and the
|
||
default controller object)
|
||
|
||
=head2 before_dispatch
|
||
|
||
Emitted right before the static file server and router start their work.
|
||
|
||
$app->hook(before_dispatch => sub {
|
||
my $c = shift;
|
||
...
|
||
});
|
||
|
||
Very useful for rewriting incoming requests and other preprocessing tasks. (Passed the default controller object)
|
||
|
||
=head2 after_static
|
||
|
||
Emitted after a static file response has been generated by the static file server.
|
||
|
||
$app->hook(after_static => sub {
|
||
my $c = shift;
|
||
...
|
||
});
|
||
|
||
Mostly used for post-processing static file responses. (Passed the default controller object)
|
||
|
||
=head2 before_routes
|
||
|
||
Emitted after the static file server determined if a static file should be served and before the router starts its
|
||
work.
|
||
|
||
$app->hook(before_routes => sub {
|
||
my $c = shift;
|
||
...
|
||
});
|
||
|
||
Mostly used for custom dispatchers and collecting metrics. (Passed the default controller object)
|
||
|
||
=head2 around_action
|
||
|
||
Emitted right before an action gets executed and wraps around it, so you have to manually forward to the next hook if
|
||
you want to continue the chain. Default action dispatching is the last hook in the chain, yours will run before it.
|
||
|
||
$app->hook(around_action => sub {
|
||
my ($next, $c, $action, $last) = @_;
|
||
...
|
||
return $next->();
|
||
});
|
||
|
||
This is a very powerful hook and should not be used lightly, it allows you for example to pass additional arguments to
|
||
actions or handle return values differently. Note that this hook can trigger more than once for the same request if
|
||
there are nested routes. (Passed a callback leading to the next hook, the current controller object, the action
|
||
callback and a flag indicating if this action is an endpoint)
|
||
|
||
=head2 before_render
|
||
|
||
Emitted before content is generated by the renderer. Note that this hook can trigger out of order due to its dynamic
|
||
nature, and with embedded applications will only work for the application that is rendering.
|
||
|
||
$app->hook(before_render => sub {
|
||
my ($c, $args) = @_;
|
||
...
|
||
});
|
||
|
||
Mostly used for pre-processing arguments passed to the renderer. (Passed the current controller object and the render
|
||
arguments)
|
||
|
||
=head2 after_render
|
||
|
||
Emitted after content has been generated by the renderer that will be assigned to the response. Note that this hook can
|
||
trigger out of order due to its dynamic nature, and with embedded applications will only work for the application that
|
||
is rendering.
|
||
|
||
$app->hook(after_render => sub {
|
||
my ($c, $output, $format) = @_;
|
||
...
|
||
});
|
||
|
||
Mostly used for post-processing dynamically generated content. (Passed the current controller object, a reference to
|
||
the content and the format)
|
||
|
||
=head2 after_dispatch
|
||
|
||
Emitted in reverse order after a response has been generated. Note that this hook can trigger out of order due to its
|
||
dynamic nature, and with embedded applications will only work for the application that is generating the response.
|
||
|
||
$app->hook(after_dispatch => sub {
|
||
my $c = shift;
|
||
...
|
||
});
|
||
|
||
Useful for rewriting outgoing responses and other post-processing tasks. (Passed the current controller object)
|
||
|
||
=head1 ATTRIBUTES
|
||
|
||
L<Mojolicious> implements the following attributes.
|
||
|
||
=head2 commands
|
||
|
||
my $commands = $app->commands;
|
||
$app = $app->commands(Mojolicious::Commands->new);
|
||
|
||
Command line interface for your application, defaults to a L<Mojolicious::Commands> object.
|
||
|
||
# Add another namespace to load commands from
|
||
push @{$app->commands->namespaces}, 'MyApp::Command';
|
||
|
||
=head2 controller_class
|
||
|
||
my $class = $app->controller_class;
|
||
$app = $app->controller_class('Mojolicious::Controller');
|
||
|
||
Class to be used for the default controller, defaults to L<Mojolicious::Controller>. Note that this class needs to have
|
||
already been loaded before the first request arrives.
|
||
|
||
=head2 home
|
||
|
||
my $home = $app->home;
|
||
$app = $app->home(Mojo::Home->new);
|
||
|
||
The home directory of your application, defaults to a L<Mojo::Home> object which stringifies to the actual path.
|
||
|
||
# Portably generate path relative to home directory
|
||
my $path = $app->home->child('data', 'important.txt');
|
||
|
||
=head2 log
|
||
|
||
my $log = $app->log;
|
||
$app = $app->log(Mojo::Log->new);
|
||
|
||
The logging layer of your application, defaults to a L<Mojo::Log> object. The level will default to either the
|
||
C<MOJO_LOG_LEVEL> environment variable, C<debug> if the L</mode> is C<development>, or C<info> otherwise. All messages
|
||
will be written to C<STDERR>, or a C<log/$mode.log> file if a C<log> directory exists.
|
||
|
||
# Log debug message
|
||
$app->log->debug('It works');
|
||
|
||
=head2 max_request_size
|
||
|
||
my $max = $app->max_request_size;
|
||
$app = $app->max_request_size(16777216);
|
||
|
||
Maximum request size in bytes, defaults to the value of L<Mojo::Message/"max_message_size">. Setting the value to C<0>
|
||
will allow requests of indefinite size. Note that increasing this value can also drastically increase memory usage,
|
||
should you for example attempt to parse an excessively large request body with the methods L<Mojo::Message/"dom"> or
|
||
L<Mojo::Message/"json">.
|
||
|
||
=head2 mode
|
||
|
||
my $mode = $app->mode;
|
||
$app = $app->mode('production');
|
||
|
||
The operating mode for your application, defaults to a value from the C<MOJO_MODE> and C<PLACK_ENV> environment
|
||
variables or C<development>.
|
||
|
||
=head2 moniker
|
||
|
||
my $moniker = $app->moniker;
|
||
$app = $app->moniker('foo_bar');
|
||
|
||
Moniker of this application, often used as default filename for configuration files and the like, defaults to
|
||
decamelizing the application class with L<Mojo::Util/"decamelize">.
|
||
|
||
=head2 plugins
|
||
|
||
my $plugins = $app->plugins;
|
||
$app = $app->plugins(Mojolicious::Plugins->new);
|
||
|
||
The plugin manager, defaults to a L<Mojolicious::Plugins> object. See the L</"plugin"> method below if you want to load
|
||
a plugin.
|
||
|
||
# Add another namespace to load plugins from
|
||
push @{$app->plugins->namespaces}, 'MyApp::Plugin';
|
||
|
||
=head2 renderer
|
||
|
||
my $renderer = $app->renderer;
|
||
$app = $app->renderer(Mojolicious::Renderer->new);
|
||
|
||
Used to render content, defaults to a L<Mojolicious::Renderer> object. For more information about how to generate
|
||
content see L<Mojolicious::Guides::Rendering>.
|
||
|
||
# Enable compression
|
||
$app->renderer->compress(1);
|
||
|
||
# Add another "templates" directory
|
||
push @{$app->renderer->paths}, '/home/sri/templates';
|
||
|
||
# Add another "templates" directory with higher precedence
|
||
unshift @{$app->renderer->paths}, '/home/sri/themes/blue/templates';
|
||
|
||
# Add another class with templates in DATA section
|
||
push @{$app->renderer->classes}, 'Mojolicious::Plugin::Fun';
|
||
|
||
=head2 routes
|
||
|
||
my $routes = $app->routes;
|
||
$app = $app->routes(Mojolicious::Routes->new);
|
||
|
||
The router, defaults to a L<Mojolicious::Routes> object. You use this in your startup method to define the url
|
||
endpoints for your application.
|
||
|
||
# Add routes
|
||
my $r = $app->routes;
|
||
$r->get('/foo/bar')->to('test#foo', title => 'Hello Mojo!');
|
||
$r->post('/baz')->to('test#baz');
|
||
|
||
# Add another namespace to load controllers from
|
||
push @{$app->routes->namespaces}, 'MyApp::MyController';
|
||
|
||
=head2 secrets
|
||
|
||
my $secrets = $app->secrets;
|
||
$app = $app->secrets([$bytes]);
|
||
|
||
Secret passphrases used for signed cookies and the like, defaults to the L</"moniker"> of this application, which is
|
||
not very secure, so you should change it!!! As long as you are using the insecure default there will be debug messages
|
||
in the log file reminding you to change your passphrase. Only the first passphrase is used to create new signatures,
|
||
but all of them for verification. So you can increase security without invalidating all your existing signed cookies by
|
||
rotating passphrases, just add new ones to the front and remove old ones from the back.
|
||
|
||
# Rotate passphrases
|
||
$app->secrets(['new_passw0rd', 'old_passw0rd', 'very_old_passw0rd']);
|
||
|
||
=head2 sessions
|
||
|
||
my $sessions = $app->sessions;
|
||
$app = $app->sessions(Mojolicious::Sessions->new);
|
||
|
||
Signed cookie based session manager, defaults to a L<Mojolicious::Sessions> object. You can usually leave this alone,
|
||
see L<Mojolicious::Controller/"session"> for more information about working with session data.
|
||
|
||
# Change name of cookie used for all sessions
|
||
$app->sessions->cookie_name('mysession');
|
||
|
||
# Disable SameSite feature
|
||
$app->sessions->samesite(undef);
|
||
|
||
=head2 static
|
||
|
||
my $static = $app->static;
|
||
$app = $app->static(Mojolicious::Static->new);
|
||
|
||
For serving static files from your C<public> directories, defaults to a L<Mojolicious::Static> object.
|
||
|
||
# Add another "public" directory
|
||
push @{$app->static->paths}, '/home/sri/public';
|
||
|
||
# Add another "public" directory with higher precedence
|
||
unshift @{$app->static->paths}, '/home/sri/themes/blue/public';
|
||
|
||
# Add another class with static files in DATA section
|
||
push @{$app->static->classes}, 'Mojolicious::Plugin::Fun';
|
||
|
||
# Remove built-in favicon
|
||
delete $app->static->extra->{'favicon.ico'};
|
||
|
||
=head2 types
|
||
|
||
my $types = $app->types;
|
||
$app = $app->types(Mojolicious::Types->new);
|
||
|
||
Responsible for connecting file extensions with MIME types, defaults to a L<Mojolicious::Types> object.
|
||
|
||
# Add custom MIME type
|
||
$app->types->type(twt => 'text/tweet');
|
||
|
||
=head2 ua
|
||
|
||
my $ua = $app->ua;
|
||
$app = $app->ua(Mojo::UserAgent->new);
|
||
|
||
A full featured HTTP user agent for use in your applications, defaults to a L<Mojo::UserAgent> object.
|
||
|
||
# Perform blocking request
|
||
say $app->ua->get('example.com')->result->body;
|
||
|
||
=head2 validator
|
||
|
||
my $validator = $app->validator;
|
||
$app = $app->validator(Mojolicious::Validator->new);
|
||
|
||
Validate values, defaults to a L<Mojolicious::Validator> object.
|
||
|
||
# Add validation check
|
||
$app->validator->add_check(foo => sub {
|
||
my ($v, $name, $value) = @_;
|
||
return $value ne 'foo';
|
||
});
|
||
|
||
# Add validation filter
|
||
$app->validator->add_filter(quotemeta => sub {
|
||
my ($v, $name, $value) = @_;
|
||
return quotemeta $value;
|
||
});
|
||
|
||
=head1 METHODS
|
||
|
||
L<Mojolicious> inherits all methods from L<Mojo::Base> and implements the following new ones.
|
||
|
||
=head2 build_controller
|
||
|
||
my $c = $app->build_controller;
|
||
my $c = $app->build_controller(Mojo::Transaction::HTTP->new);
|
||
my $c = $app->build_controller(Mojolicious::Controller->new);
|
||
|
||
Build default controller object with L</"controller_class">.
|
||
|
||
# Render template from application
|
||
my $foo = $app->build_controller->render_to_string(template => 'foo');
|
||
|
||
=head2 build_tx
|
||
|
||
my $tx = $app->build_tx;
|
||
|
||
Build L<Mojo::Transaction::HTTP> object and emit L</"after_build_tx"> hook.
|
||
|
||
=head2 config
|
||
|
||
my $hash = $app->config;
|
||
my $foo = $app->config('foo');
|
||
$app = $app->config({foo => 'bar', baz => 23});
|
||
$app = $app->config(foo => 'bar', baz => 23);
|
||
|
||
Application configuration.
|
||
|
||
# Remove value
|
||
my $foo = delete $app->config->{foo};
|
||
|
||
# Assign multiple values at once
|
||
$app->config(foo => 'test', bar => 23);
|
||
|
||
=head2 defaults
|
||
|
||
my $hash = $app->defaults;
|
||
my $foo = $app->defaults('foo');
|
||
$app = $app->defaults({foo => 'bar', baz => 23});
|
||
$app = $app->defaults(foo => 'bar', baz => 23);
|
||
|
||
Default values for L<Mojolicious::Controller/"stash">, assigned for every new request.
|
||
|
||
# Remove value
|
||
my $foo = delete $app->defaults->{foo};
|
||
|
||
# Assign multiple values at once
|
||
$app->defaults(foo => 'test', bar => 23);
|
||
|
||
=head2 dispatch
|
||
|
||
$app->dispatch(Mojolicious::Controller->new);
|
||
|
||
The heart of every L<Mojolicious> application, calls the L</"static"> and L</"routes"> dispatchers for every request
|
||
and passes them a L<Mojolicious::Controller> object.
|
||
|
||
=head2 handler
|
||
|
||
$app->handler(Mojo::Transaction::HTTP->new);
|
||
$app->handler(Mojolicious::Controller->new);
|
||
|
||
Sets up the default controller and emits the L</"around_dispatch"> hook for every request.
|
||
|
||
=head2 helper
|
||
|
||
$app->helper(foo => sub {...});
|
||
|
||
Add or replace a helper that will be available as a method of the controller object and the application object, as well
|
||
as a function in C<ep> templates. For a full list of helpers that are available by default see
|
||
L<Mojolicious::Plugin::DefaultHelpers> and L<Mojolicious::Plugin::TagHelpers>.
|
||
|
||
# Helper
|
||
$app->helper(cache => sub { state $cache = {} });
|
||
|
||
# Application
|
||
$app->cache->{foo} = 'bar';
|
||
my $result = $app->cache->{foo};
|
||
|
||
# Controller
|
||
$c->cache->{foo} = 'bar';
|
||
my $result = $c->cache->{foo};
|
||
|
||
# Template
|
||
% cache->{foo} = 'bar';
|
||
%= cache->{foo}
|
||
|
||
=head2 hook
|
||
|
||
$app->hook(after_dispatch => sub {...});
|
||
|
||
Extend L<Mojolicious> with hooks, which allow code to be shared with all requests indiscriminately, for a full list of
|
||
available hooks see L</"HOOKS">.
|
||
|
||
# Dispatchers will not run if there's already a response code defined
|
||
$app->hook(before_dispatch => sub {
|
||
my $c = shift;
|
||
$c->render(text => 'Skipped static file server and router!')
|
||
if $c->req->url->path->to_route =~ /do_not_dispatch/;
|
||
});
|
||
|
||
=head2 new
|
||
|
||
my $app = Mojolicious->new;
|
||
my $app = Mojolicious->new(moniker => 'foo_bar');
|
||
my $app = Mojolicious->new({moniker => 'foo_bar'});
|
||
|
||
Construct a new L<Mojolicious> application and call L</"startup">. Will automatically detect your home directory. Also
|
||
sets up the renderer, static file server, a default set of plugins and an L</"around_dispatch"> hook with the default
|
||
exception handling.
|
||
|
||
=head2 plugin
|
||
|
||
$app->plugin('some_thing');
|
||
$app->plugin('some_thing', foo => 23);
|
||
$app->plugin('some_thing', {foo => 23});
|
||
$app->plugin('SomeThing');
|
||
$app->plugin('SomeThing', foo => 23);
|
||
$app->plugin('SomeThing', {foo => 23});
|
||
$app->plugin('MyApp::Plugin::SomeThing');
|
||
$app->plugin('MyApp::Plugin::SomeThing', foo => 23);
|
||
$app->plugin('MyApp::Plugin::SomeThing', {foo => 23});
|
||
|
||
Load a plugin, for a full list of example plugins included in the L<Mojolicious> distribution see
|
||
L<Mojolicious::Plugins/"PLUGINS">.
|
||
|
||
=head2 server
|
||
|
||
$app->server(Mojo::Server->new);
|
||
|
||
Emits the L</"before_server_start"> hook.
|
||
|
||
=head2 start
|
||
|
||
$app->start;
|
||
$app->start(@ARGV);
|
||
|
||
Start the command line interface for your application. For a full list of commands that are available by default see
|
||
L<Mojolicious::Commands/"COMMANDS">. Note that the options C<-h>/C<--help>, C<--home> and C<-m>/C<--mode>, which are
|
||
shared by all commands, will be parsed from C<@ARGV> during compile time.
|
||
|
||
# Always start daemon
|
||
$app->start('daemon', '-l', 'http://*:8080');
|
||
|
||
=head2 startup
|
||
|
||
$app->startup;
|
||
|
||
This is your main hook into the application, it will be called at application startup. Meant to be overloaded in a
|
||
subclass.
|
||
|
||
sub startup {
|
||
my $self = shift;
|
||
...
|
||
}
|
||
|
||
=head1 HELPERS
|
||
|
||
In addition to the L</"ATTRIBUTES"> and L</"METHODS"> above you can also call helpers on L<Mojolicious> objects. This
|
||
includes all helpers from L<Mojolicious::Plugin::DefaultHelpers> and L<Mojolicious::Plugin::TagHelpers>. Note that
|
||
application helpers are always called with a new default controller object, so they can't depend on or change
|
||
controller state, which includes request, response and stash.
|
||
|
||
# Call helper
|
||
say $app->dumper({foo => 'bar'});
|
||
|
||
# Longer version
|
||
say $app->build_controller->helpers->dumper({foo => 'bar'});
|
||
|
||
=head1 BUNDLED FILES
|
||
|
||
The L<Mojolicious> distribution includes a few files with different licenses that have been bundled for internal use.
|
||
|
||
=head2 Mojolicious Artwork
|
||
|
||
Copyright (C) 2010-2020, Sebastian Riedel.
|
||
|
||
Licensed under the CC-SA License, Version 4.0 L<http://creativecommons.org/licenses/by-sa/4.0>.
|
||
|
||
=head2 jQuery
|
||
|
||
Copyright (C) jQuery Foundation.
|
||
|
||
Licensed under the MIT License, L<http://creativecommons.org/licenses/MIT>.
|
||
|
||
=head2 prettify.js
|
||
|
||
Copyright (C) 2006, 2013 Google Inc..
|
||
|
||
Licensed under the Apache License, Version 2.0 L<http://www.apache.org/licenses/LICENSE-2.0>.
|
||
|
||
=head1 CODE NAMES
|
||
|
||
Every major release of L<Mojolicious> has a code name, these are the ones that have been used in the past.
|
||
|
||
8.0, C<Supervillain> (U+1F9B9)
|
||
|
||
7.0, C<Doughnut> (U+1F369)
|
||
|
||
6.0, C<Clinking Beer Mugs> (U+1F37B)
|
||
|
||
5.0, C<Tiger Face> (U+1F42F)
|
||
|
||
4.0, C<Top Hat> (U+1F3A9)
|
||
|
||
3.0, C<Rainbow> (U+1F308)
|
||
|
||
2.0, C<Leaf Fluttering In Wind> (U+1F343)
|
||
|
||
1.0, C<Snowflake> (U+2744)
|
||
|
||
=head1 SPONSORS
|
||
|
||
=over 2
|
||
|
||
=item
|
||
|
||
L<Stix|https://stix.no> sponsored the creation of the Mojolicious logo (designed by Nicolai Graesdal) and transferred
|
||
its copyright to Sebastian Riedel.
|
||
|
||
=item
|
||
|
||
Some of the work on this distribution has been sponsored by L<The Perl Foundation|http://www.perlfoundation.org>.
|
||
|
||
=back
|
||
|
||
=head1 PROJECT FOUNDER
|
||
|
||
Sebastian Riedel, C<kraih@mojolicious.org>
|
||
|
||
=head1 CORE DEVELOPERS
|
||
|
||
Current voting members of the core team in alphabetical order:
|
||
|
||
=over 2
|
||
|
||
CandyAngel, C<candyangel@mojolicious.org>
|
||
|
||
Christopher Rasch-Olsen Raa, C<christopher@mojolicious.org>
|
||
|
||
Dan Book, C<grinnz@mojolicious.org>
|
||
|
||
Jan Henning Thorsen, C<batman@mojolicious.org>
|
||
|
||
Joel Berger, C<jberger@mojolicious.org>
|
||
|
||
Marcus Ramberg, C<marcus@mojolicious.org>
|
||
|
||
=back
|
||
|
||
The following members of the core team are currently on hiatus:
|
||
|
||
=over 2
|
||
|
||
Abhijit Menon-Sen, C<ams@cpan.org>
|
||
|
||
Glen Hinkle, C<tempire@cpan.org>
|
||
|
||
=back
|
||
|
||
=head1 CREDITS
|
||
|
||
In alphabetical order:
|
||
|
||
=over 2
|
||
|
||
Adam Kennedy
|
||
|
||
Adriano Ferreira
|
||
|
||
Al Newkirk
|
||
|
||
Alex Efros
|
||
|
||
Alex Salimon
|
||
|
||
Alexander Karelas
|
||
|
||
Alexey Likhatskiy
|
||
|
||
Anatoly Sharifulin
|
||
|
||
Andre Parker
|
||
|
||
Andre Vieth
|
||
|
||
Andreas Guldstrand
|
||
|
||
Andreas Jaekel
|
||
|
||
Andreas Koenig
|
||
|
||
Andrew Fresh
|
||
|
||
Andrew Nugged
|
||
|
||
Andrey Khozov
|
||
|
||
Andrey Kuzmin
|
||
|
||
Andy Grundman
|
||
|
||
Aristotle Pagaltzis
|
||
|
||
Ashley Dev
|
||
|
||
Ask Bjoern Hansen
|
||
|
||
Audrey Tang
|
||
|
||
Ben Tyler
|
||
|
||
Ben van Staveren
|
||
|
||
Benjamin Erhart
|
||
|
||
Bernhard Graf
|
||
|
||
Breno G. de Oliveira
|
||
|
||
Brian Duggan
|
||
|
||
Brian Medley
|
||
|
||
Burak Gursoy
|
||
|
||
Ch Lamprecht
|
||
|
||
Charlie Brady
|
||
|
||
Chas. J. Owens IV
|
||
|
||
Chase Whitener
|
||
|
||
Christian Hansen
|
||
|
||
chromatic
|
||
|
||
Curt Tilmes
|
||
|
||
Daniel Kimsey
|
||
|
||
Daniel Mantovani
|
||
|
||
Danijel Tasov
|
||
|
||
Dagfinn Ilmari Manns<6E>ker
|
||
|
||
Danny Thomas
|
||
|
||
David Davis
|
||
|
||
David Webb
|
||
|
||
Diego Kuperman
|
||
|
||
Dmitriy Shalashov
|
||
|
||
Dmitry Konstantinov
|
||
|
||
Dominik Jarmulowicz
|
||
|
||
Dominique Dumont
|
||
|
||
Dotan Dimet
|
||
|
||
Douglas Christopher Wilson
|
||
|
||
Ettore Di Giacinto
|
||
|
||
Eugen Konkov
|
||
|
||
Eugene Toropov
|
||
|
||
Flavio Poletti
|
||
|
||
Gisle Aas
|
||
|
||
Graham Barr
|
||
|
||
Graham Knop
|
||
|
||
Henry Tang
|
||
|
||
Hideki Yamamura
|
||
|
||
Hiroki Toyokawa
|
||
|
||
Ian Goodacre
|
||
|
||
Ilya Chesnokov
|
||
|
||
Ilya Rassadin
|
||
|
||
James Duncan
|
||
|
||
Jan Jona Javorsek
|
||
|
||
Jan Schmidt
|
||
|
||
Jaroslav Muhin
|
||
|
||
Jesse Vincent
|
||
|
||
Johannes Plunien
|
||
|
||
John Kingsley
|
||
|
||
Jonathan Yu
|
||
|
||
Josh Leder
|
||
|
||
Kamen Naydenov
|
||
|
||
Karen Etheridge
|
||
|
||
Kazuhiro Shibuya
|
||
|
||
Kevin Old
|
||
|
||
Kitamura Akatsuki
|
||
|
||
Klaus S. Madsen
|
||
|
||
Knut Arne Bjorndal
|
||
|
||
Lars Balker Rasmussen
|
||
|
||
Lee Johnson
|
||
|
||
Leon Brocard
|
||
|
||
Magnus Holm
|
||
|
||
Maik Fischer
|
||
|
||
Mark Fowler
|
||
|
||
Mark Grimes
|
||
|
||
Mark Stosberg
|
||
|
||
Martin McGrath
|
||
|
||
Marty Tennison
|
||
|
||
Matt S Trout
|
||
|
||
Matthew Lineen
|
||
|
||
Maksym Komar
|
||
|
||
Maxim Vuets
|
||
|
||
Michael Gregorowicz
|
||
|
||
Michael Harris
|
||
|
||
Michael Jemmeson
|
||
|
||
Mike Magowan
|
||
|
||
Mirko Westermeier
|
||
|
||
Mons Anderson
|
||
|
||
Moritz Lenz
|
||
|
||
Neil Watkiss
|
||
|
||
Nic Sandfield
|
||
|
||
Nils Diewald
|
||
|
||
Oleg Zhelo
|
||
|
||
Olivier Mengue
|
||
|
||
Pascal Gaudette
|
||
|
||
Paul Evans
|
||
|
||
Paul Robins
|
||
|
||
Paul Tomlin
|
||
|
||
Pavel Shaydo
|
||
|
||
Pedro Melo
|
||
|
||
Peter Edwards
|
||
|
||
Pierre-Yves Ritschard
|
||
|
||
Piotr Roszatycki
|
||
|
||
Quentin Carbonneaux
|
||
|
||
Rafal Pocztarski
|
||
|
||
Randal Schwartz
|
||
|
||
Richard Elberger
|
||
|
||
Rick Delaney
|
||
|
||
Robert Hicks
|
||
|
||
Robin Lee
|
||
|
||
Roland Lammel
|
||
|
||
Roy Storey
|
||
|
||
Ryan Jendoubi
|
||
|
||
Salvador Fandino
|
||
|
||
Santiago Zarate
|
||
|
||
Sascha Kiefer
|
||
|
||
Scott Wiersdorf
|
||
|
||
Sebastian Paaske Torholm
|
||
|
||
Sergey Zasenko
|
||
|
||
Simon Bertrang
|
||
|
||
Simone Tampieri
|
||
|
||
Shoichi Kaji
|
||
|
||
Shu Cho
|
||
|
||
Skye Shaw
|
||
|
||
Stanis Trendelenburg
|
||
|
||
Stefan Adams
|
||
|
||
Steffen Ullrich
|
||
|
||
Stephan Kulow
|
||
|
||
Stephane Este-Gracias
|
||
|
||
Stevan Little
|
||
|
||
Steve Atkins
|
||
|
||
Tatsuhiko Miyagawa
|
||
|
||
Terrence Brannon
|
||
|
||
Tianon Gravi
|
||
|
||
Tomas Znamenacek
|
||
|
||
Tudor Constantin
|
||
|
||
Ulrich Habel
|
||
|
||
Ulrich Kautz
|
||
|
||
Uwe Voelker
|
||
|
||
Veesh Goldman
|
||
|
||
Viacheslav Tykhanovskyi
|
||
|
||
Victor Engmark
|
||
|
||
Viliam Pucik
|
||
|
||
Wes Cravens
|
||
|
||
William Lindley
|
||
|
||
Yaroslav Korshak
|
||
|
||
Yuki Kimoto
|
||
|
||
Zak B. Elep
|
||
|
||
Zoffix Znet
|
||
|
||
=back
|
||
|
||
=head1 COPYRIGHT AND LICENSE
|
||
|
||
Copyright (C) 2008-2020, Sebastian Riedel and others.
|
||
|
||
This program is free software, you can redistribute it and/or modify it under the terms of the Artistic License version
|
||
2.0.
|
||
|
||
=head1 SEE ALSO
|
||
|
||
L<https://github.com/mojolicious/mojo>, L<Mojolicious::Guides>, L<https://mojolicious.org>.
|
||
|
||
=cut
|