ASP4
view release on metacpan or search on metacpan
lib/ASP4.pm view on Meta::CPAN
domain => ".example.com", # works for *.example.com
domain => "www.example.com", # will ONLY work for www.example.com
# Path:
path => "/some/folder/" # will ONLY work within /some/folder/ on your website
);
=head3 $Response->Include( $path, %args )
ASP4's C<$Response> object offers 3 different include methods.
<!-- Normal SSI-style Include -->
<!-- #include virtual="/includes/page.asp" -->
If you want to supply arguments to the included ASP script you can use C<< $Response->Include($path, \%args) >>
# Add the output of C</includes/page.asp> to the current output buffer:
my %args = ( foo => "bar" );
$Response->Include( $Server->MapPath("/includes/page.asp"), \%args );
C<\%args> is optional.
Within the included ASP script, C<\%args> is accessible like this:
<%
my ($self, $context, $args) = @_;
%>
=head3 $Response->TrapInclude( $path, %args )
Or if you need to capture the result of executing an ASP script and use it within
a variable, use C<< $Response->TrapInclude($path, \%args) >>
# Capture the output of C</includes/page.asp>:
my %args = ( foo => "bar" );
my $html = $Response->TrapInclude( $Server->MapPath("/includes/page.asp"), \%args );
C<\%args> is optional.
Within the included ASP script, C<\%args> is accessible like this:
<%
my ($self, $context, $args) = @_;
%>
=head2 $Session
The C<$Session> object is an instance of a subclass of L<ASP4::SessionStateManager>
(depending on your website's configuration).
The C<$Session> object is a simple blessed hashref and should be used like a hashref.
Examples:
=head3 Set a session variable
$Session->{foo} = "bar";
$Session->{thing} = {
banana => "yellow",
cherry => "red",
peach => "pink,
};
=head3 Get a session variable
my $foo = $Session->{foo};
=head3 $Session->save()
Called automatically at the end of every successful request, causes any changes
to the C<$Session> to be saved to the database.
=head3 $Session->reset()
Call C<< $Session->reset() >> to clear all the data out of the session and save
it to the database.
=head2 $Config
The ASP4 C<$Config> object is stored in a simple JSON format on disk, and accessible
everywhere within your entire ASP4 application as the global C<$Config> object.
If ever you find yourself in a place without a C<$Config> object, you can get one
like this:
use ASP4::ConfigLoader;
my $Config = ASP4::ConfigLoader->load();
See L<ASP4::Config> for full details on the ASP4 C<$Config> object and its usage.
=head2 $Stash
The C<$Stash> is a simple hashref that is guaranteed to be the exact same hashref
throughout the entire lifetime of a request.
Anything placed within the C<$Stash> at the very beginning of processing a request -
such as in a RequestFilter - will still be there at the very end of the request -
as in a RegisterCleanup handler.
Use the C<$Stash> as a great place to store a piece of data for the duration of
a single request.
=head1 DATABASE
While ASP4 B<does not require> its users to choose any specific database (eg: MySQL or PostgreSQL)
or ORM (object-relational mapper) the B<recommended> ORM is L<Class::DBI::Lite>
since it has been completely and thoroughly tested to be 100% compatible with ASP4.
For full documentation about L<Class::DBI::Lite> please view its documentation.
B<NOTE:> L<Class::DBI::Lite> must be installed in addition to ASP4 as it is a separate library.
=head1 ASP4 QuickStart
Here is an example project to get things going.
In the C<data_connections.main> section of C<conf/asp4-config.json> you should have
something like this:
...
lib/ASP4.pm view on Meta::CPAN
}
1;# return true:
C<lib/App/db/message.pm>
package App::db::message;
use strict;
use warnings 'all';
use base 'App::db::model';
__PACKAGE__->set_up_table('messages');
__PACKAGE__->belongs_to(
sender =>
'App::db::user' =>
'from_user_id'
);
__PACKAGE__->belongs_to(
recipient =>
'App::db::user' =>
'to_user_id'
);
1;# return true:
Create your MasterPage like this:
File: C<htdocs/masters/global.asp>
<%@ MasterPage %>
<!DOCTYPE html>
<html>
<head>
<title><asp:ContentPlaceHolder id="meta_title"></asp:ContentPlaceHolder></title>
<meta charset="utf-8" />
</head>
<body>
<h1><asp:ContentPlaceHolder id="headline"></asp:ContentPlaceHolder></h1>
<asp:ContentPlaceHolder id="main_content"></asp:ContentPlaceHolder>
</body>
</html>
File: C<htdocs/index.asp>
<%@ Page UseMasterPage="/masters/global.asp" %>
<asp:Content PlaceHolderID="meta_title">Register</asp:Content>
<asp:Content PlaceHolderID="headline">Register</asp:Content>
<asp:Content PlaceHolderID="main_content">
<%
# Sticky forms work like this:
if( my $args = $Session->{__lastArgs} ) {
map { $Form->{$_} = $args->{$_} } keys %$args;
}
# Our validation errors:
my $errors = $Session->{validation_errors} || { };
$::err = sub {
my $field = shift;
my $error = $errors->{$field} or return;
%><span class="field_error"><%= $Server->HTMLEncode( $error ) %></span><%
};
%>
<form id="register_form" method="post" action="/handlers/myapp.register">
<p>
<label>Email:</label>
<input type="text" name="email" value="<%= $Server->HTMLEncode( $Form->{email} ) %>" />
<% $::err->("email"); %>
</p>
<p>
<label>Password:</label>
<input type="password" name="password" />
<% $::err->("password"); %>
</p>
<p>
<label>Confirm Password:</label>
<input type="password" name="password2" />
<% $::err->("password2"); %>
</p>
<p>
<input type="submit" value="Register Now" />
</p>
</form>
</asp:Content>
The form submits to the URL C</handlers/app.register> which means C<handlers/app/register.pm>
File: C<handlers/app/register.pm>
package app::register;
use strict;
use warnings 'all';
use base 'ASP4::FormHandler';
use vars __PACKAGE__->VARS; # Import $Response, $Form, $Session, etc
use App::db::user;
sub run {
my ($self, $context) = @_;
# If there is an error, return the user to the registration page:
if( my $errors = $self->validate() ) {
$Session->{validation_errors} = $errors;
$Session->{__lastArgs} = $Form;
$Session->save;
return $Response->Redirect( $ENV{HTTP_REFERER} );
}
# Create the user:
my $user = eval {
App::db::user->do_transaction(sub {
return App::db::user->create(
email => $Form->{email},
password => $Form->{password},
);
});
};
if( $@ ) {
# There was an error:
$Session->{validation_errors} = {email => "Server error. Sorry!"};
$Session->{__lastArgs} = $Form;
$Session->save;
return $Response->Redirect( $ENV{HTTP_REFERER} );
}
else {
# No error - Sign them in:
$Session->{user_id} = $user->id;
$Session->{msg} = "Thank you for registering!";
$Session->save;
# Redirect to /profile.asp:
return $Response->Redirect("/profile.asp");
}# end if()
}
sub validate {
my ($self) = @_;
$self->trim_form;
my $errors = { };
no warnings 'uninitialized';
# email:
if( length($Form->{email}) ) {
# Basic email validation:
unless( $Form->{email} =~ m{[^@]+@[^@]+\.[^@]+} ) {
$errors->{email} = "Invalid email address";
}
}
else {
$errors->{email} = "Required";
}
# password:
unless( length($Form->{password} ) {
$errors->{password} = "Required";
}
# password2:
if( length($Form->{password2}) ) {
if( length($Form->{password}) ) {
unless( $Form->{password} eq $Form->{password2} ) {
$errors->{password2} = "Passwords don't match";
}
}
}
else {
$errors->{password2} = "Required";
}
# Bail out of we already have errors:
return $errors if keys %$errors;
# See if the user already exists:
if( App::db::user->count_search( email => $Form->{email} ) ) {
$errors->{email} = "Already in use";
}
# Errors or not?:
keys %$errors ? return $errors : return;
}
1;# return true:
File: C<htdocs/profile.asp>
<%@ Page UseMasterPage="/masters/global.asp" %>
<asp:Content PlaceHolderID="meta_title">My Profile</asp:Content>
<asp:Content PlaceHolderID="headline">My Profile</asp:Content>
<asp:Content PlaceHolderID="main_content">
<%
if( my $msg = $Session->{msg} ) {
%>
<div class="message"><%= $msg %></div>
<%
}# end if()
%>
<%
# Get our $user:
use App::db::user;
my $user = App::db::user->retrieve( $Session->{user_id} );
%>
<div style="float: left; width: 40%; border-right: solid 1px #000;">
<h3>Incoming Messages</h3>
<%
foreach my $msg ( $user->messages_in(undef, { order_by => "created_on ASC"} ) ) {
%>
<div class="msg">
<span class="from"><%= $msg->sender->email %></span> says:<br/>
<div class="body"><%= $Server->HTMLEncode( $msg->body ) %></div>
<span class="date"><%= $msg->created_on %></span>
</div>
<%
}# end foreach()
%>
</div>
<div style="float: right; width: 40%; border: dotted 1px #000;">
<h3>Send New Message</h3>
<form id="send_form" method="post" action="/handlers/app.send">
<p>
<label>Recipient:</label>
<select name="to_user_id">
<%
my @users = App::db::user->search_where({
user_id => {'!=' => $user->id }
}, {
order_by => "email"
});
foreach my $user ( @users ) {
%>
<option value="<%= $user->id %>"><%= $Server->HTMLEncode( $user->email ) %></option>
<%
}# end foreach()
%>
( run in 0.818 second using v1.01-cache-2.11-cpan-39bf76dae61 )