ASP4

 view release on metacpan or  search on metacpan

README.markdown  view on Meta::CPAN


The `$Session` object is an instance of a subclass of [ASP4::SessionStateManager](http://search.cpan.org/perldoc?ASP4::SessionStateManager)
(depending on your website's configuration).

The `$Session` object is a simple blessed hashref and should be used like a hashref.

Examples:

### Set a session variable

    $Session->{foo} = "bar";

    $Session->{thing} = {
      banana  => "yellow",
      cherry  => "red",
      peach   => "pink,
    };

### Get a session variable

    my $foo = $Session->{foo};

### $Session->save()

Called automatically at the end of every successful request, causes any changes
to the `$Session` to be saved to the database.

### $Session->reset()

Call `$Session->reset()` to clear all the data out of the session and save 
it to the database.

## $Config

The ASP4 `$Config` object is stored in a simple JSON format on disk, and accessible
everywhere within your entire ASP4 application as the global `$Config` object.

If ever you find yourself in a place without a `$Config` object, you can get one
like this:

    use ASP4::ConfigLoader;
    my $Config = ASP4::ConfigLoader->load();

See [ASP4::Config](http://search.cpan.org/perldoc?ASP4::Config) for full details on the ASP4 `$Config` object and its usage.

## $Stash

The `$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 `$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 `$Stash` as a great place to store a piece of data for the duration of
a single request.

# DATABASE

While ASP4 __does not require__ its users to choose any specific database (eg: MySQL or PostgreSQL)
or ORM (object-relational mapper) the __recommended__ ORM is [Class::DBI::Lite](http://search.cpan.org/perldoc?Class::DBI::Lite)
since it has been completely and thoroughly tested to be 100% compatible with ASP4.

For full documentation about [Class::DBI::Lite](http://search.cpan.org/perldoc?Class::DBI::Lite) please view its documentation.

__NOTE:__ [Class::DBI::Lite](http://search.cpan.org/perldoc?Class::DBI::Lite) must be installed in addition to ASP4 as it is a separate library.

# ASP4 QuickStart

Here is an example project to get things going.

In the `data_connections.main` section of `conf/asp4-config.json` you should have
something like this:

    ...
      "main": {
        "dsn":              "DBI:mysql:database_name:data.mywebsite.com",
        "username":         "db-username",
        "password":         "db-pAsswOrd"
      }
    ...

Suppose you had the following tables in your database:

    create table users (
      user_id     bigint unsigned not null primary key auto_increment,
      email       varchar(200) not null,
      password    char(32) not null,
      created_on  timestamp not null default current_timestamp,
      unique(email)
    ) engine=innodb charset=utf8;
    

    create table messages (
      message_id    bigint unsigned not null primary key auto_increment,
      from_user_id  bigint unsigned not null,
      to_user_id    bigint unsigned not null,
      subject       varchar(100) not null,
      body          text,
      created_on    timestamp not null default current_timestamp,
      foreign key fk_messages_to_senders (from_user_id) references users (user_id) on delete cascade,
      foreign key fk_messages_to_recipients (to_user_id) references users (user_id) on delete cascade
    ) engine=innodb charset=utf8;

__NOTE:__ It's best to assign every ASP4 application its own namespace.  For this
example the namespace is `App::db::`

Create the file `lib/App::db/model.pm` and add the following lines:

    package App::db::model;
    

    use strict;
    use warnings 'all';
    use base 'Class::DBI::Lite::mysql';
    use ASP4::ConfigLoader;
    

    # Get our configuration object:
    my $Config = ASP4::ConfigLoader->load();
    

README.markdown  view on Meta::CPAN


    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: `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: `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 `/handlers/app.register` which means `handlers/app/register.pm`

File: `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} );
    }
    

README.markdown  view on Meta::CPAN

    

    <%
      # 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()
    %>
          </select>
        </p>
        <p>
          <label>Subject:</label>
          <input type="text" name="subject" maxlength="100" />
        </p>
        <p>
          <label>Message:</label><br/>
          <textarea name="body"></textarea>
        </p>
        <p>
          <input type="submit" value="Send Message" />
        </p>
      </form>
    </div>
    </asp:Content>

The form submits to `/handlers/app.send` which maps to `handlers/app/send.pm`

File: `handlers/app/send.pm`

    package app::send;
    

    use strict;
    use warnings 'all';
    use base 'ASP4::FormHandler';
    use vars __PACKAGE__->VARS;
    use App::db::user;
    use App::db::message;
    

    sub run {
      my ($self, $context) = @_;
      

    # Create the message:
    my $msg = eval {
      App::db::message->do_transaction(sub {
        my $msg = App::db::message->create(
          from_user_id  => $Session->{user_id},
          to_user_id    => $Form->{to_user_id},
          subject       => $Form->{subject},
          body          => $Form->{body},
        );
        

        # Send an email to the recipient:
        $Server->Mail(
          from        => 'root@localhost',
          'reply-to'  => $msg->sender->email,
          to          => $msg->recipient->email,
          subject     => 'New in-club message',
          message     => <<"MSG",
    Dear user,
    

    Another user (@{[ $msg->sender->email ]}) has sent you an in-club message.
    

    Please login and view it on your profile at http://$ENV{HTTP_HOST}/
    

    Yours,
    The "In Club"
    MSG
        );
        

        # Finally:
        return $msg;
      });
    };
    

      if( $@ ) {
        $Session->{msg} = "Error: Your message could not be sent.";
        $Session->save;



( run in 0.721 second using v1.01-cache-2.11-cpan-39bf76dae61 )