DBIx::Class::ResultSourceHandle - Serializable pointers to ResultSource instances


DBIx-Class documentation Contained in the DBIx-Class distribution.

Index


Code Index:

NAME

Top

DBIx::Class::ResultSourceHandle - Serializable pointers to ResultSource instances

DESCRIPTION

Top

Currently instances of this class are used to allow proper serialization of ResultSources (which may contain unserializable elements like CODE references).

Originally this module was used to remove the fixed link between Rows/ResultSets and the actual result source objects in order to obviate the need of keeping a schema instance constantly in scope, while at the same time avoiding leaks due to circular dependencies. This is however no longer needed after introduction of a proper mutual-assured-destruction contract between a Schema instance and its ResultSource registrants.

METHODS

Top

new

resolve

Resolve the moniker into the actual ResultSource object

STORABLE_freeze

Freezes a handle.

STORABLE_thaw

Thaws frozen handle. Resets the internal schema reference to the package variable $thaw_schema. The recommended way of setting this is to use $schema->thaw($ice) which handles this for you.

AUTHOR

Top

Ash Berlin <ash@cpan.org>


DBIx-Class documentation Contained in the DBIx-Class distribution.
package DBIx::Class::ResultSourceHandle;

use strict;
use warnings;

use base qw/DBIx::Class/;

use DBIx::Class::Exception;
use Try::Tiny;

use namespace::clean;

use overload
    q/""/ => sub { __PACKAGE__ . ":" . shift->source_moniker; },
    fallback => 1;

__PACKAGE__->mk_group_accessors('simple' => qw/schema source_moniker _detached_source/);

# Schema to use when thawing.
our $thaw_schema;

sub new {
  my ($class, $args) = @_;
  my $self = bless $args, ref $class || $class;

  unless( ($self->{schema} || $self->{_detached_source}) && $self->{source_moniker} ) {
    my $err = 'Expecting a schema instance and a source moniker';
    $self->{schema}
      ? $self->{schema}->throw_exception($err)
      : DBIx::Class::Exception->throw($err)
  }

  $self;
}

sub resolve {
  return $_[0]->{schema}->source($_[0]->source_moniker) if $_[0]->{schema};

  $_[0]->_detached_source || DBIx::Class::Exception->throw( sprintf (
    # vague error message as this is never supposed to happen
    "Unable to resolve moniker '%s' - please contact the dev team at %s",
    $_[0]->source_moniker,
    'http://search.cpan.org/dist/DBIx-Class/lib/DBIx/Class.pm#GETTING_HELP/SUPPORT',
  ), 'full_stacktrace');
}

sub STORABLE_freeze {
  my ($self, $cloning) = @_;

  my $to_serialize = { %$self };

  delete $to_serialize->{schema};
  delete $to_serialize->{_detached_source};
  $to_serialize->{_frozen_from_class} = $self->{schema}
    ? $self->{schema}->class($self->source_moniker)
    : $self->{_detached_source}->result_class
  ;

  Storable::nfreeze($to_serialize);
}

sub STORABLE_thaw {
  my ($self, $cloning, $ice) = @_;
  %$self = %{ Storable::thaw($ice) };

  my $from_class = delete $self->{_frozen_from_class};

  if( $thaw_schema ) {
    $self->schema( $thaw_schema );
  }
  elsif( my $rs = $from_class->result_source_instance ) {
    # in the off-chance we are using CDBI-compat and have leaked $schema already
    if( my $s = try { $rs->schema } ) {
      $self->schema( $s );
    }
    else {
      $rs->source_name( $self->source_moniker );
      $rs->{_detached_thaw} = 1;
      $self->_detached_source( $rs );
    }
  }
  else {
    DBIx::Class::Exception->throw(
      "Thaw failed - original result class '$from_class' does not exist on this system"
    );
  }
}

1;