Commit | Line | Data |
aec3eff1 |
1 | package DBIx::Class::ResultSourceHandle; |
2 | |
3 | use strict; |
4 | use warnings; |
aec3eff1 |
5 | |
6 | use base qw/DBIx::Class/; |
7 | |
4376a157 |
8 | use Try::Tiny; |
4376a157 |
9 | use namespace::clean; |
10 | |
aec3eff1 |
11 | use overload |
3441fd57 |
12 | q/""/ => sub { __PACKAGE__ . ":" . shift->source_moniker; }, |
aec3eff1 |
13 | fallback => 1; |
14 | |
4376a157 |
15 | __PACKAGE__->mk_group_accessors('simple' => qw/schema source_moniker _detached_source/); |
aec3eff1 |
16 | |
4146e3da |
17 | # Schema to use when thawing. |
18 | our $thaw_schema; |
19 | |
aec3eff1 |
20 | =head1 NAME |
21 | |
4376a157 |
22 | DBIx::Class::ResultSourceHandle - Serializable pointers to ResultSource instances |
aec3eff1 |
23 | |
24 | =head1 DESCRIPTION |
25 | |
4376a157 |
26 | Currently instances of this class are used to allow proper serialization of |
27 | L<ResultSources|DBIx::Class::ResultSource> (which may contain unserializable |
28 | elements like C<CODE> references). |
aec3eff1 |
29 | |
4376a157 |
30 | Originally this module was used to remove the fixed link between |
31 | L<Rows|DBIx::Class::Row>/L<ResultSets|DBIx::Class::ResultSet> and the actual |
32 | L<result source objects|DBIx::Class::ResultSource> in order to obviate the need |
33 | of keeping a L<schema instance|DBIx::Class::Schema> constantly in scope, while |
34 | at the same time avoiding leaks due to circular dependencies. This is however |
35 | no longer needed after introduction of a proper mutual-assured-destruction |
36 | contract between a C<Schema> instance and its C<ResultSource> registrants. |
aec3eff1 |
37 | |
38 | =head1 METHODS |
39 | |
40 | =head2 new |
41 | |
42 | =cut |
43 | |
44 | sub new { |
4376a157 |
45 | my ($class, $args) = @_; |
46 | my $self = bless $args, ref $class || $class; |
aec3eff1 |
47 | |
4376a157 |
48 | unless( ($self->{schema} || $self->{_detached_source}) && $self->{source_moniker} ) { |
49 | my $err = 'Expecting a schema instance and a source moniker'; |
50 | $self->{schema} |
51 | ? $self->{schema}->throw_exception($err) |
52 | : DBIx::Class::Exception->throw($err) |
53 | } |
aec3eff1 |
54 | |
4376a157 |
55 | $self; |
aec3eff1 |
56 | } |
57 | |
58 | =head2 resolve |
59 | |
3441fd57 |
60 | Resolve the moniker into the actual ResultSource object |
aec3eff1 |
61 | |
62 | =cut |
63 | |
4376a157 |
64 | sub resolve { |
65 | return $_[0]->{schema}->source($_[0]->source_moniker) if $_[0]->{schema}; |
66 | |
67 | $_[0]->_detached_source || DBIx::Class::Exception->throw( sprintf ( |
68 | # vague error message as this is never supposed to happen |
69 | "Unable to resolve moniker '%s' - please contact the dev team at %s", |
70 | $_[0]->source_moniker, |
32250d01 |
71 | DBIx::Class::_ENV_::HELP_URL, |
4376a157 |
72 | ), 'full_stacktrace'); |
73 | } |
aec3eff1 |
74 | |
7137528d |
75 | =head2 STORABLE_freeze |
76 | |
77 | Freezes a handle. |
78 | |
79 | =cut |
80 | |
aec3eff1 |
81 | sub STORABLE_freeze { |
4376a157 |
82 | my ($self, $cloning) = @_; |
4146e3da |
83 | |
4376a157 |
84 | my $to_serialize = { %$self }; |
d4daee7b |
85 | |
4376a157 |
86 | delete $to_serialize->{schema}; |
87 | delete $to_serialize->{_detached_source}; |
88 | $to_serialize->{_frozen_from_class} = $self->{schema} |
89 | ? $self->{schema}->class($self->source_moniker) |
90 | : $self->{_detached_source}->result_class |
91 | ; |
7cfda9a6 |
92 | |
3b80fa31 |
93 | Storable::nfreeze($to_serialize); |
aec3eff1 |
94 | } |
95 | |
7137528d |
96 | =head2 STORABLE_thaw |
97 | |
4146e3da |
98 | Thaws frozen handle. Resets the internal schema reference to the package |
8273e845 |
99 | variable C<$thaw_schema>. The recommended way of setting this is to use |
323e0bd0 |
100 | C<< $schema->thaw($ice) >> which handles this for you. |
7137528d |
101 | |
102 | =cut |
103 | |
aec3eff1 |
104 | sub STORABLE_thaw { |
4376a157 |
105 | my ($self, $cloning, $ice) = @_; |
3b80fa31 |
106 | %$self = %{ Storable::thaw($ice) }; |
4376a157 |
107 | |
108 | my $from_class = delete $self->{_frozen_from_class}; |
109 | |
110 | if( $thaw_schema ) { |
111 | $self->schema( $thaw_schema ); |
112 | } |
113 | elsif( my $rs = $from_class->result_source_instance ) { |
114 | # in the off-chance we are using CDBI-compat and have leaked $schema already |
115 | if( my $s = try { $rs->schema } ) { |
116 | $self->schema( $s ); |
3a81f59b |
117 | } |
118 | else { |
4376a157 |
119 | $rs->source_name( $self->source_moniker ); |
120 | $rs->{_detached_thaw} = 1; |
121 | $self->_detached_source( $rs ); |
3a81f59b |
122 | } |
4376a157 |
123 | } |
124 | else { |
125 | DBIx::Class::Exception->throw( |
126 | "Thaw failed - original result class '$from_class' does not exist on this system" |
127 | ); |
128 | } |
aec3eff1 |
129 | } |
130 | |
a2bd3796 |
131 | =head1 FURTHER QUESTIONS? |
4146e3da |
132 | |
a2bd3796 |
133 | Check the list of L<additional DBIC resources|DBIx::Class/GETTING HELP/SUPPORT>. |
134 | |
135 | =head1 COPYRIGHT AND LICENSE |
136 | |
137 | This module is free software L<copyright|DBIx::Class/COPYRIGHT AND LICENSE> |
138 | by the L<DBIx::Class (DBIC) authors|DBIx::Class/AUTHORS>. You can |
139 | redistribute it and/or modify it under the same terms as the |
140 | L<DBIx::Class library|DBIx::Class/COPYRIGHT AND LICENSE>. |
4146e3da |
141 | |
142 | =cut |
143 | |
aec3eff1 |
144 | 1; |