| examples/single-file-apps/form-app.psgi | |||
|---|---|---|---|
| Criterion | Covered | Total | % |
| statement | 19 | 19 | 100.0 |
| branch | n/a | ||
| condition | n/a | ||
| subroutine | 5 | 5 | 100.0 |
| pod | n/a | ||
| total | 24 | 24 | 100.0 |
| line | stmt | bran | cond | sub | pod | time | code |
|---|---|---|---|---|---|---|---|
| 1 | #!perl | ||||||
| 2 | 1 | 1 | 1815 | use v5.36; | |||
| 1 | 6 | ||||||
| 3 | |||||||
| 4 | ####################################################################### | ||||||
| 5 | # Main module | ||||||
| 6 | |||||||
| 7 | package PXF::Example::FormApp { | ||||||
| 8 | 1 | 1 | 8 | use PlackX::Framework; | |||
| 1 | 3 | ||||||
| 1 | 9 | ||||||
| 9 | } | ||||||
| 10 | |||||||
| 11 | ####################################################################### | ||||||
| 12 | # Set up routes using Router DSL | ||||||
| 13 | |||||||
| 14 | package PXF::Example::FormApp::Routes { | ||||||
| 15 | 1 | 1 | 8 | use PXF::Example::FormApp::Router; | |||
| 1 | 2 | ||||||
| 1 | 10 | ||||||
| 16 | |||||||
| 17 | our $counter = 0; | ||||||
| 18 | |||||||
| 19 | my $app_name = 'My Example App'; | ||||||
| 20 | my %credentials = (username => 'larry', password => 'perl'); | ||||||
| 21 | |||||||
| 22 | my $style = <<~INDENTED_HEREDOC; | ||||||
| 23 | body { | ||||||
| 24 | color: #333; font-family: Tahoma, Sans-serif; | ||||||
| 25 | margin: 1em; | ||||||
| 26 | } | ||||||
| 27 | form { | ||||||
| 28 | border: 1px solid #ddd; | ||||||
| 29 | padding: 1em; | ||||||
| 30 | } | ||||||
| 31 | form label { | ||||||
| 32 | display: block; | ||||||
| 33 | } | ||||||
| 34 | form input { | ||||||
| 35 | display: block; | ||||||
| 36 | margin-top: 0.25em; | ||||||
| 37 | margin-bottom: 0.75em; | ||||||
| 38 | } | ||||||
| 39 | INDENTED_HEREDOC | ||||||
| 40 | |||||||
| 41 | # Filters, a bad way to to do templating | ||||||
| 42 | filter before => sub ($request, $response) { | ||||||
| 43 | my $title = __PACKAGE__; | ||||||
| 44 | $response->print(qq{ | ||||||
| 45 | |||||||
| 46 | |||||||
| 47 | |||||||
| 48 | |
||||||
| 49 | |||||||
| 50 | |||||||
| 51 | |||||||
| 52 | }); | ||||||
| 53 | return; | ||||||
| 54 | }; | ||||||
| 55 | |||||||
| 56 | filter after => sub ($request, $response) { | ||||||
| 57 | $response->print("\n"); | ||||||
| 58 | return; | ||||||
| 59 | }; | ||||||
| 60 | |||||||
| 61 | # Demonstrate a global filter - add signature | ||||||
| 62 | global_filter after => sub ($request, $response) { | ||||||
| 63 | return unless $response->content_type =~ m|text/html|; | ||||||
| 64 | $response->print("\n\n\n"); | ||||||
| 65 | return; # return nothing to continue | ||||||
| 66 | }; | ||||||
| 67 | |||||||
| 68 | # Root request | ||||||
| 69 | route '/' => sub ($request, $response) { | ||||||
| 70 | $response->print(qq{ | ||||||
| 71 | $app_name |
||||||
| 72 | Please Log In to continue. |
||||||
| 73 | }); | ||||||
| 74 | return $response; | ||||||
| 75 | }; | ||||||
| 76 | |||||||
| 77 | # Different route | ||||||
| 78 | route '/login' => sub ($request, $response) { | ||||||
| 79 | my $message = $request->stash->{'message'} || 'Enter your credentials below.'; | ||||||
| 80 | my $want_method = $request->param('method') // 'post'; | ||||||
| 81 | $response->print(qq{ | ||||||
| 82 | $app_name: Log In |
||||||
| 83 | $message |
||||||
| 84 | |||||||
| 85 | |||||||
| 86 | |||||||
| 87 | |||||||
| 88 | |||||||
| 89 | }); | ||||||
| 90 | return $response; | ||||||
| 91 | }; | ||||||
| 92 | |||||||
| 93 | # Demonstrate HTTP request method | ||||||
| 94 | route { post => ['/login-submit','/login/submit'] } => sub ($request, $response) { | ||||||
| 95 | my $username = $request->param('username'); | ||||||
| 96 | my $password = $request->param('password'); | ||||||
| 97 | |||||||
| 98 | unless ($username eq $credentials{'username'} and $password eq $credentials{'password'}) { | ||||||
| 99 | # Here we show the login page again with the "reroute" feature. | ||||||
| 100 | # We could also use the flash_redirect feature instead. | ||||||
| 101 | $request->stash->{'message'} = "Incorrect username ($username) or password ($password)."; | ||||||
| 102 | return $request->reroute('/login'); | ||||||
| 103 | } | ||||||
| 104 | |||||||
| 105 | $response->print(qq{ | ||||||
| 106 | $app_name |
||||||
| 107 | Welcome back, $username. |
||||||
| 108 | }); | ||||||
| 109 | |||||||
| 110 | return $response; | ||||||
| 111 | }; | ||||||
| 112 | |||||||
| 113 | route { get => '/login/submit' } => sub ($request, $response) { | ||||||
| 114 | $response->status(405); | ||||||
| 115 | $response->print(qq{ | ||||||
| 116 | Method Not Allowed |
||||||
| 117 | You cannot login with a GET request. Please try again. |
||||||
| 118 | }); | ||||||
| 119 | return $response; | ||||||
| 120 | }; | ||||||
| 121 | |||||||
| 122 | # Demonstrate a callback (cleanup handler) | ||||||
| 123 | route '/callback' => sub ($request, $response) { | ||||||
| 124 | my $supports_cleanup = $request->env->{'psgix.cleanup'}; | ||||||
| 125 | |||||||
| 126 | $response->add_cleanup_callback(sub ($env) { | ||||||
| 127 | say "Cleanup callback: sleeping for 1 second..."; | ||||||
| 128 | say "(server does not support cleanup callbacks, so this will cause blocking...)" unless $supports_cleanup; | ||||||
| 129 | sleep 1; | ||||||
| 130 | $counter++; | ||||||
| 131 | }); | ||||||
| 132 | $response->print(qq{ | ||||||
| 133 | Cleanup Callback Example |
||||||
| 134 | Callback added. Request $request, response $response. |
||||||
| 135 | }); | ||||||
| 136 | $response->print("Server does NOT support cleanup!") unless $supports_cleanup. | ||||||
| 137 | return $response; | ||||||
| 138 | }; | ||||||
| 139 | |||||||
| 140 | # Demonstrate flash | ||||||
| 141 | route '/flash/set/:message' => sub ($request, $response) { | ||||||
| 142 | $response->flash($request->route_param('message')); | ||||||
| 143 | $response->redirect('/flash/view'); | ||||||
| 144 | return $response; | ||||||
| 145 | }; | ||||||
| 146 | |||||||
| 147 | route '/flash/view' => sub ($request, $response) { | ||||||
| 148 | $response->print('Flash message shown below!'); | ||||||
| 149 | $response->print('If you refresh the page, it will disappear.'); | ||||||
| 150 | $response->print($request->flash); | ||||||
| 151 | return $response; | ||||||
| 152 | }; | ||||||
| 153 | } | ||||||
| 154 | |||||||
| 155 | ####################################################################### | ||||||
| 156 | # Routing without DSL | ||||||
| 157 | |||||||
| 158 | package PXF::Example::FormApp::Routes::NonDSL { | ||||||
| 159 | 1 | 1 | 10 | use PXF::Example::FormApp::Router (); | |||
| 1 | 3 | ||||||
| 1 | 159 | ||||||
| 160 | |||||||
| 161 | # Add routes (actions can be coderefs or names of functions as strings) | ||||||
| 162 | PXF::Example::FormApp::Router->add_route('/page/{pagenum:\d+}/view' => 'page_nondsl'); | ||||||
| 163 | |||||||
| 164 | # Route actions | ||||||
| 165 | 1 | 1 | 3 | sub page_nondsl ($request, $response) { | |||
| 1 | 3 | ||||||
| 1 | 4 | ||||||
| 1 | 2 | ||||||
| 166 | 1 | 6 | my $page = $request->route_param('pagenum'); | ||||
| 167 | 1 | 7 | $response->print('No DSL Example'); |
||||
| 168 | 1 | 5 | $response->print("You are viewing page $page. \n"); |
||||
| 169 | 1 | 4 | return $response; | ||||
| 170 | } | ||||||
| 171 | } | ||||||
| 172 | |||||||
| 173 | ####################################################################### | ||||||
| 174 | # Return the application coderef | ||||||
| 175 | |||||||
| 176 | PXF::Example::FormApp->app; |