Catalyst::Plugin::Session::Store::Jifty::DBI - Store your session with Jifty::DBI


Catalyst-Plugin-Session-Store-Jifty-DBI documentation Contained in the Catalyst-Plugin-Session-Store-Jifty-DBI distribution.

Index


Code Index:

NAME

Top

Catalyst::Plugin::Session::Store::Jifty::DBI - Store your session with Jifty::DBI

SYNOPSIS

Top

  # prepare a table like this.
  # note that we use "session_id" instead of simple "id",
  # as "id" is usually reserved as serial by Jifty::DBI
  # (which is configurable but changing this is not recommended).
  package MyApp::Schema::Session;
  use Jifty::DBI::Schema;
  use Jifty::DBI::Record schema {
    column session_id
      => type is 'char(72)', is mandatory, is distinct, is indexed;
    column session_data => type is 'text';
    column expires      => type is 'integer';
  };

  # and a model
  package MyApp::Model::DB;
  use base qw( Catalyst::Model::Jifty::DBI );
  __PACKAGE__->config->{schema_base} = 'MyApp::Schema';

  # and your app.
  MyApp->config('Plugin::Session' => {
    expires => 3600,
    moniker => 'DB::Session',
  });

  # then in an action
  $c->session->[foo} = 'bar'; # will be saved

DESCRIPTION

Top

This storage module will store session data in a database using a Jifty::DBI model.

CONFIGURATION

Top

These parameters are placed in the configuration hash under the session key.

expires

The expires column in your table will be set with the expiration value. Note that no automatic cleanup is done. You can use delete_expired_session method with Catalyst::Plugin::Scheduler, but most probably you may want to implement your own cleanup script with raw Jifty::DBI (or Catalyst::Model::Jifty::DBI) for speed and stability.

moniker

specify the moniker to access your session table (to get a session record) via $c->model(). This configuration is mandatory. If you dare, you also can set moniker_collection to specify the moniker to get a collection of session records (but you usually don't need this).

columns

by default, this module uses the column names shown above, but if you want to change some of these, you can give this a hash reference like this:

  MyApp->config('Plugin::Session' => {
    expires => 3600,
    moniker => 'DB::Session',
    columns => {
      id           => 'sid',
      session_data => 'body',
      expires      => 'until',
    },
  });

use_custom_serialization

If you want to use Jifty::DBI::Filters to serialize/deserialize session data, set this to true. This may be handy when you want to use other Jifty::DBI's features like validation.

METHODS

Top

get_session_data

store_session_data

delete_session_data

delete_expired_sessions

setup_session

These are implementations of the required methods for a store. See Catalyst::Plugin::Session::Store.

SEE ALSO

Top

Catalyst::Plugin::Session, Catalyst::Plugin::Session::Store::DBI, Catalyst::Plugin::Session::Store::DOD

AUTHOR

Top

Kenichi Ishigaki, <ishigaki@cpan.org>

COPYRIGHT AND LICENSE

Top


Catalyst-Plugin-Session-Store-Jifty-DBI documentation Contained in the Catalyst-Plugin-Session-Store-Jifty-DBI distribution.

package Catalyst::Plugin::Session::Store::Jifty::DBI;

use strict;
use warnings;
use base qw( Catalyst::Plugin::Session::Store );
use Storable qw( nfreeze thaw );
use MIME::Base64;
use Catalyst::Exception;
use MRO::Compat;
use mro 'c3';

our $VERSION = '0.03';

sub setup_session {
  my $c = shift;

  $c->maybe::next::method(@_);

  unless ( $c->_session_plugin_config->{moniker} ) {
    Catalyst::Exception->throw(
      "Session::Store::Jifty::DBI: 'moniker' is missing"
    );
  }
  $c->_session_plugin_config->{moniker_collection}
    ||= $c->_session_plugin_config->{moniker} . 'Collection';

  my %column = %{ $c->_session_plugin_config->{columns} || {} };
  unless ( $column{id} && $column{session_data} && $column{expires} ) {
    $column{id}           ||= 'session_id';
    $column{session_data} ||= 'session_data';
    $column{expires}      ||= 'expires';
    $c->_session_plugin_config->{columns} = \%column;
  }
}

sub get_session_data {
  my ($c, $key) = @_;

  my $moniker = $c->_session_plugin_config->{moniker};
  my %column  = %{ $c->_session_plugin_config->{columns} };

  my $record = $c->model($moniker);
  if ( my ($sid) = $key =~ /^expires:(.*)/ ) {
    $key = "session:$sid";
    $record->load_by_cols( $column{id} => $key );
    return $record->_value( $column{expires} );
  }
  else {
    $record->load_by_cols( $column{id} => $key );
    my $data = $record->_value( $column{session_data} );
    return ( $c->_session_plugin_config->{use_custom_serialization} )
      ? $data
      : thaw( decode_base64( $data ) );
  }
  return;
}

sub store_session_data {
  my ($c, $key, $data) = @_;

  my $moniker = $c->_session_plugin_config->{moniker};
  my %column  = %{ $c->_session_plugin_config->{columns} };

  my $record = $c->model($moniker);
  if ( my ($sid) = $key =~ /^expires:(.*)/ ) {
    $key = "session:$sid";
    $record->load_by_cols( $column{id} => $key );
    if ( $record->id ) {
      $record->_set(
        column => $column{expires},
        value  => $c->session_expires,
      );
    }
  }
  else {
    unless ( $c->_session_plugin_config->{use_custom_serialization} ) {
      $data = encode_base64( nfreeze( $data ) );
    }

    my $expires = ( $key =~ /^(?:session|flash):/ )
                ? $c->session_expires
                : undef;

    $record->load_by_cols( $column{id} => $key );
    if ( $record->id ) {
      $c->model($moniker)->_handle->begin_transaction;
      eval {
        $record->_set(
          column => $column{session_data},
          value  => $data,
        );
        $record->_set(
          column => $column{expires},
          value  => $expires,
        );
      };
      $@ ? $c->model($moniker)->_handle->rollback
         : $c->model($moniker)->_handle->commit;
    }
    else {
      $record->create(
        $column{id}           => $key,
        $column{session_data} => $data,
        $column{expires}      => $expires,
      );
    }
  }
  return;
}

sub delete_session_data {
  my ($c, $key) = @_;

  return if $key =~ /^expires:/;

  my $moniker = $c->_session_plugin_config->{moniker};
  my %column  = %{ $c->_session_plugin_config->{columns} };

  my $record = $c->model($moniker);
  $record->load_by_cols( $column{id} => $key );
  $record->delete;
}

sub delete_expired_sessions {
  my $c = shift;

  # XXX: this must be much better to do with simple_query

  my $moniker = $c->_session_plugin_config->{moniker_collection};
  my %column  = %{ $c->_session_plugin_config->{columns} };

  my $collection = $c->model($moniker);
  $collection->limit(
    column   => $column{expires},
    value    => undef,
    operator => 'IS NOT',
  );
  $collection->limit(
    column   => $column{expires},
    value    => time(),
    operator => '<',
  );

  while( my $record = $collection->next ) {
    $record->delete;
  }
}

1;

__END__