PlackX-Framework
view release on metacpan or search on metacpan
lib/PlackX/Framework/Handler.pm view on Meta::CPAN
use v5.36;
package PlackX::Framework::Handler {
use PXF::Util ();
use Scalar::Util qw(blessed);
use HTTP::Status qw(status_message);
my %globals;
our $psgix_streaming; # memoized, but in an "our" var so tests can change it
sub use_global_request_response { } # Override in subclass to turn on
sub global_request ($class) { $globals{$class->app_namespace}->[0] }
sub global_response ($class) { $globals{$class->app_namespace}->[1] }
sub error_response ($class, $code) { [$code, [], [status_message($code)." ($code)"]] } # Override for nicer message
#
# App assembly section
#
sub build_app ($class, %options) {
# Freeze the router
my $rt_engine = ($class->app_namespace . '::Router::Engine')->instance;
$rt_engine->freeze;
# Honestly, it is probably better for the user to use Plack::Builder
# or URLMap or Cascade instead of doing this, but we do it here for
# convenience in development environments, at least for now. Think about
# removing this feature at a later date.
my $serve_static_files = delete $options{'serve_static_files'};
my $static_docroot = delete $options{'static_docroot'};
die "Unknown options: " . join(', ', keys %options) if %options;
my $main_app = sub ($env) { psgi_response($class->handle_request($env, undef, $rt_engine)) };
my $file_app = ($serve_static_files and do {
require Plack::App::File;
Plack::App::File->new(root => $static_docroot)->to_app;
});
# if app_base is specified, use URLMap
if (my $app_base = $class->app_base) {
require Plack::App::URLMap;
my $mapper = Plack::App::URLMap->new;
$mapper->map($app_base => $main_app);
$mapper->map('/' => $file_app) if $file_app;
return $mapper->to_app;
}
# Static file app with no app_base, so try one, try the other if it's 404
# (basically our own cascade whereas we could use Plack::App::Cascade).
# We prefer to serve the app's 404 page if the file app also returns 404
# because it is easier to customize the 404 page with PXF.
# Add a later date we might add a feature to intercept all 4xx and 5xx
# error codes at the last possible moment and render a user-defined page.
return sub ($env) {
my $main_resp = $main_app->($env);
return $main_resp if ref $main_resp and $main_resp->[0] != 404;
my $file_resp = $file_app->($env);
return $file_resp if ref $file_resp and $file_resp->[0] != 404;
return $main_resp;
} if $file_app;
# no app_base, no static file app, just return the main app
return $main_app;
}
sub app_base ($class) {
my $base = eval { $class->app_namespace->app_base } || eval { $class->app_namespace->uri_prefix } || '';
$base = '/'.$base if $base and length $base and substr($base,0,1) ne '/';
return $base;
}
#
# Request handling section
#
sub handle_request ($class, $env_or_req, $maybe_resp = undef, $maybe_rt_engine = undef) {
my $app_namespace = $class->app_namespace;
# Get or create default request and response objects
my $env = $class->env_or_req_to_env($env_or_req);
my $request = $class->env_or_req_to_req($env_or_req);
my $response = $maybe_resp || ($app_namespace . '::Response')->new->set_defaults;
# Memoize server info and maybe set request/response globals
$psgix_streaming = $env->{'psgi.streaming'} ? !!1 : !!0
if !defined $psgix_streaming;
$globals{$app_namespace} = [$request, $response]
if $class->use_global_request_response;
# Set up stash
my $stash = ($request->stash or $response->stash or {});
$request->stash($stash);
$response->stash($stash);
# Maybe set up Templating, if loaded
if (PXF::Util::is_module_loaded($app_namespace . '::Template')) {
eval {
my $template = ($app_namespace . '::Template')->new($response);
$template->set(STASH => $stash, REQUEST => $request, RESPONSE => $response);
$response->template($template);
} or do {
warn "$app_namespace\::Template module loaded, but unable to set up template: $@"
. " (Hint: Did you use/import from it or set up templating manually?)\n";
};
}
# Clear flash if set, set response defaults, and route request
$response->flash(undef) if $request->flash;
return $class->route_request($request, $response, $maybe_rt_engine);
}
( run in 0.951 second using v1.01-cache-2.11-cpan-2398b32b56e )