NAME

Apache2::Controller::Session - Apache2::Controller PerlHeaderParserHandler for Apache::Session

SYNOPSIS

Set your A2C session subclass as a PerlHeaderParserHandler.

This example assumes use of Apache2::Controller::Session::Cookie.

# cookies will get path => /somewhere
<Location /somewhere>

    # see Apache2::Controller::Dispatch for dispatch subclass info
    PerlInitHandler         MyApp::Dispatch

    PerlSetVar  A2CSessionCookieName    myappsessid
    PerlSetVar  A2CSessionClass         Apache::Session::MySQL

    PerlHeaderParserHandler MyApp::Session
</Location>

In controllers, tied session hash is $r->pnotes->{session}.

In this example above, you implement get_options() in your session subclass to return the options hashref to tie() for Apache::Session::MySQL.

If you do not implement get_options(), it will try to create directories to use Apache::Session::File using /tmp/a2c_sessions/<request hostname>/ and /var/lock/a2c_sessions/<request hostname>

DESCRIPTION

Your session module uses an Apache2::Controller::Session tracker module as a base and you specify your Apache::Session options either as config variables or by implementing a method <getoptions()>.

Instead of having a bunch of different options for all the different Apache::Session types, it's easier for me to make you provide a method session_options() in your subclass that will return a has of the appropriate options for your chosen session store.

CONFIG ALTERNATIVE 1: directives or PerlSetVar variables

If you do not implement a special getoptions() method or use settings other than these, these are the default:

<Location /elsewhere>
    PerlHeaderParserHandler MyApp::ApacheSessionFile

    # until directives work, use this PerlSetVar syntax:
    PerlSetVar A2CSessionClass Apache::Session::File
    PerlSetVar A2CSessionOptions "Directory /tmp/sessions LockDirectory /var/lock/sessions"

    # under future fixed Apache2::Controller::Directives directives
    A2CSessionClass    Apache::Session::File
    A2CSessionOptions  Directory       /tmp/sessions 
    A2CSessionOptions  LockDirectory   /var/lock/sessions
</Location>

Until directives work and the kludgey PerlSetVar syntax goes away, spaces are not allowed in the argument values. Warning! The kludgey PerlSetVar syntax will go away when directives work properly.

CONFIG ALTERNATIVE 2: YourApp::YourSessionClass->get_options()

Implement get_options() in your subclass to return the final options hashref for your Apache::Session session type.

For example, if your app uses DBIx::Class, maybe you want to go ahead and init your schema so you can get the database handle directly and pass that to your session class. or if you use Apache::DBI, connect and put it in pnotes to save for your own use later.

Here's a code example for Location /somewhere above:

package MyApp::Session;
use strict;
use warnings FATAL => 'all';

use base qw( Apache2::Controller::Session::Cookie );

use English '-no_match_vars';
use Apache2::Controller::X;

sub get_options {
    my ($self) = @_;  # $self inherits Apache2::Controller::Session,
                      # Apache2::Controller::Session::Cookie,
                      # Apache2::Request, Apache2::RequestRec, etc...
    eval {
        $self->pnotes->{dbh} ||= DBI->connect(
            'dbi:mysql:database=myapp;host=mydbhost';
            'myuser', 'mypassword'
        );
    };
    Apache2::Controller::X->throw("cannot connect to DB: $EVAL_ERROR")
        if $EVAL_ERROR;
    
    my $dbh = $self->pnotes->{dbh};    # save handle for later use
                                       # in controllers, etc.

    return {
        Handle      => $dbh,
        LockHandle  => $dbh,
    };
}

If you do it this way or use Apache::DBI, be careful about transactions. See "DATABASE TRANSACTION SAFETY" below.

# ...

In your controller module, access the session in $self->pnotes->{session}.

package MyApp::Controller::SomeWhere::Overtherainbow;
# ...
sub default {
    my ($self) = @_;

    my $session = $self->pnotes->{session};
    $session->{foo} = 'bar';

    # session will be saved by a PerlCleanupHandler
    # that was automatically pushed by Apache2::Controller::Session

    # and in my example

    return Apache2::Const::HTTP_OK;
}

DATABASE TRANSACTION SAFETY

When this handler runs, it ties the session into a special hash that it keeps internally, and loads a copy into $r->pnotes->{session}. So, modifying the session hash is fine, as long as you do not dereference it, or as long as you save your changes back to $r->pnotes->{session}.

No changes are auto-committed. The one in pnotes is copied back into the tied session hash in a PerlCleanupHandler, after the server finishes output and closes the connection to the client. If the connection is detected to be aborted in the PerlLogHandler phase, changes are NOT saved into the session object in the PerlCleanupHandler phase.

If you implemented get_options() as per above and decided to save your $dbh for later use in your controllers, feel free to start transactions and use them normally. Just make sure you use "eval" in perlfunc correctly and roll back or commit your transactions.

If you decide to push a PerlCleanupHandler to roll back transactions for broken connections or something, be aware that this handler pushes a cleanup handler closure that saves the copy in pnotes back into the tied hash. So, depending on what order you want, whether you want to save the session before or after your database cleanup handler, you may have to re-order the PerlCleanupHandler stack with "get_handlers" in Apache2::RequestUtil and set_handlers().

IMPLEMENTING TRACKER SUBCLASSES

See Apache2::Controller::Session::Cookie for how to implement a custom tracker subclass. This implements $sid = get_session_id() which gets a session id from a cookie, and set_session_id($sid) which sets the session id in the cookie.

Perhaps some custom tracker subclass would implement get_session_id() to get the session_id out of the request query params, and set_session_id() would push a PerlOutputFilterHandler to post-process all other handler output and append the session id param onto any url links that refer to our site. That would be cool... release your own plug-in. If you wanted to do it with combined cookies and url params in this way you could overload get_session_id() and set_session_id(), etc. etc.

COOKIES

Apache2::Controller itself implements its own handler() subroutine, but other A2C handler modules <use base> Apache2::Controller::NonResponseBase.

For the most part the other A2C handlers do not need to construct the Apache2::Request object, but this one constructs it to get at the cookies with Apache2::Cookie.

It puts the results of <Apache2::Cookie::Jar-new()>> into <$r-pnotes->{cookie_jar}>>, or uses the ones there if it finds them already captured. See "get_cookie_jar" in Apache2::Controller::Methods. Maybe.

ERRORS

<Apache2::Controller::Session> will throw an error exception if the session setup encounters an error.

If the session should not be saved in the event your Apache2::Controller controller subroutine traps an <$EVAL_ERROR>, then your controller should set boolean flag <$r-notes->{connection_closed}>>

METHODS

process

The process() method attaches or creates a session, and pushes a PerlCleanupHandler closure to save the session after the end of the request.

It sets the session id cookie with an expiration that you set in your subclass as our $expiration = ... in a format that is passed to Apache2::Cookie. (i.e. '3M', '2D', etc.) Don't set that if you want them to expire at the end of the browser session.

get_options

The default get_options method uses Apache2::Session::File.

Default settings try to create subdirectories under /tmp/a2c_sessions and /var/lock/a2c_sessions which are named for the hostname of the current request, such as the virtual host name.

If you use Windows or want to do something differently, use your own settings or overload get_options().

If you use Windows, you're chicken. Live free!

SEE ALSO

Apache2::Controller::Session::Cookie,

Apache::Session,

Apache2::Controller::Dispatch,

Apache2::Controller,

AUTHOR

Mark Hedges, <hedges at scriptdolphin.org>

COPYRIGHT & LICENSE

Copyright 2008 Mark Hedges, all rights reserved.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.