File Coverage

blib/lib/Class/Persist/Proxy.pm
Criterion Covered Total %
statement 12 12 100.0
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 16 16 100.0


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             Class::Persist::Proxy - Proxy for an object not loaded yet
4              
5             =head1 SYNOPSIS
6              
7             use Class::Persist::Proxy;
8             $proxy = Class::Persist::Proxy->new();
9             $proxy->class( "AClass" );
10             $proxy->owner( $owner );
11             $real = $proxy->load();
12            
13             =head1 DESCRIPTION
14              
15             Framework to replace objects in the DB by Proxy objects.
16             This allows delayed loading of objects.
17             A proxy acts as the real object itself, it should be transparent.
18             When a method is called on the proxy, the real object is loaded in place of the proxy.
19             If owner() is defined, it will autoload the object based on owner id,
20             otherwise it will load the object based on real_id.
21              
22             =head1 INHERITANCE
23              
24             Class::Persist::Base
25              
26             =head1 METHODS
27              
28             =head2 class( $class )
29              
30             =cut
31              
32             package Class::Persist::Proxy;
33 1     1   4088 use strict;
  1         4  
  1         69  
34 1     1   7 use warnings;
  1         2  
  1         47  
35 1     1   6 use Scalar::Util qw( blessed );
  1         3  
  1         553  
36 1     1   10 use base qw( Class::Persist::Base );
  1         2  
  1         224  
37             __PACKAGE__->mk_accessors( qw(real_id) );
38              
39             our $AUTOLOAD;
40              
41              
42              
43             =head2 oid( $id )
44              
45             Tries hard to return the oid of the object proxied,
46             if it fails, returns the proxy oid.
47              
48             =cut
49              
50             sub oid {
51             my $self = shift;
52             return $self->set($Class::Persist::ID_FIELD, shift) if @_;
53             my $id = $self->real_id();
54             unless ($id) {
55             if ($self->get('owner')) {
56             $self->load() or return;
57             $id = $self->get($Class::Persist::ID_FIELD);
58             }
59             else {
60             $id = $self->SUPER::oid();
61             }
62             }
63             $id;
64             }
65              
66              
67             =head2 class( $class )
68              
69             Get / set class.
70             If no class is given, tries to guess using Class::Persist::Tracker
71              
72             =cut
73              
74             sub class {
75             my $self = shift;
76             return $self->set('class', shift) if @_;
77              
78             unless ($self->get('class')) {
79             require Class::Persist::Tracker;
80             my $tracker = Class::Persist::Tracker->load($self->oid)
81             or return $self->record('Class::Persist::Error::DB::NotFound', "object " . $self->oid . " not found", 1);
82             $self->set('class', $tracker->class);
83             }
84             return $self->get('class');
85             }
86              
87             =head2 owner( $obj )
88              
89             Get / set owner.
90             The owner is automatically proxied.
91              
92             =cut
93              
94             sub owner {
95             my $self = shift;
96             if (my ($owner) = @_) {
97             blessed($owner) or Class::Persist::Error::InvalidParameters->throw(text => "owner should be an object");
98             unless ($owner->isa('Class::Persist::Proxy')) {
99             my $proxy = Class::Persist::Proxy->new();
100             $proxy->class( ref $owner );
101             $proxy->oid( $owner->oid );
102             $owner = $proxy;
103             }
104             return $self->set('owner', $owner);
105             }
106             return $self->get('owner') || $self->load->owner;
107             }
108              
109              
110             =head2 load()
111              
112             Replace the proxy by its target object
113              
114             =cut
115              
116             sub load {
117             my $self = shift;
118             my $class = $self->class or return $self->record('Class::Persist::Error::InvalidParameters', "A class should be defined in proxy", 1);
119             $self->loadModule( $class ) or return;
120              
121             my $obj = $class->load($self->get('owner') || $self->oid);
122              
123             unless ($obj) {
124             require Class::Persist::Tracker;
125             if (my $tracker = Class::Persist::Tracker->load($self->get('owner') || $self->oid)) {
126             if (my $object = $tracker->object) {
127             $self->_duplicate_from($object);
128             bless $self => ref($object);
129             return $self;
130             }
131             }
132             return $self->record('Class::Persist::Error::DB::NotFound', "Could not load $class for $self", 1)
133             }
134              
135             $self->_duplicate_from( $obj );
136             bless $self => $class;
137             }
138              
139              
140             =head2 proxy( $obj )
141              
142             Replace object by proxy
143              
144             =cut
145              
146             sub proxy {
147             my $class = shift;
148             my $obj = shift;
149             my $owner = shift;
150             return $obj if $obj->isa(__PACKAGE__);
151             $obj->isa('Class::Persist') or Class::Persist::Error::InvalidParameters->throw(text => "object to proxy should be a Class::Persist");
152            
153             $class->loadModule( ref $obj ) or return;
154             my $self = $class->new();
155             $self->class( ref $obj );
156             if ($owner) {
157             $self->owner( $owner );
158             }
159             $self->real_id( $obj->oid );
160             $obj->_duplicate_from( $self );
161             bless $obj => $class;
162             }
163              
164              
165             sub AUTOLOAD {
166             my $self = shift;
167             $self = $self->load() or return; # die "Can't find in DB from ".(caller)[0]." line ".(caller)[2];
168             my $meth = substr($AUTOLOAD, rindex($AUTOLOAD, ':') + 1);
169             my $can = $self->can($meth) or EO::Error::Method::NotFound->throw(text => "Method $meth unknownin class ".ref($self));
170             $can->($self, @_);
171             }
172              
173             sub DESTROY { 1 }
174              
175             sub clone {
176             my $self = shift;
177             $self = $self->load or return;
178             return $self->clone(@_);
179             }
180              
181             1;
182              
183             =head1 SEE ALSO
184              
185             Class::Persist
186              
187             =head1 AUTHOR
188              
189             Fotango
190              
191             =cut
192              
193             # Local Variables:
194             # mode:CPerl
195             # cperl-indent-level: 2
196             # indent-tabs-mode: nil
197             # End: