File Coverage

blib/lib/ORM/History.pm
Criterion Covered Total %
statement 54 109 49.5
branch 12 42 28.5
condition 0 6 0.0
subroutine 4 10 40.0
pod 3 7 42.8
total 73 174 41.9


line stmt bran cond sub pod time code
1             #
2             # DESCRIPTION
3             # PerlORM - Object relational mapper (ORM) for Perl. PerlORM is Perl
4             # library that implements object-relational mapping. Its features are
5             # much similar to those of Java's Hibernate library, but interface is
6             # much different and easier to use.
7             #
8             # AUTHOR
9             # Alexey V. Akimov
10             #
11             # COPYRIGHT
12             # Copyright (C) 2005-2006 Alexey V. Akimov
13             #
14             # This library is free software; you can redistribute it and/or
15             # modify it under the terms of the GNU Lesser General Public
16             # License as published by the Free Software Foundation; either
17             # version 2.1 of the License, or (at your option) any later version.
18             #
19             # This library is distributed in the hope that it will be useful,
20             # but WITHOUT ANY WARRANTY; without even the implied warranty of
21             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22             # Lesser General Public License for more details.
23             #
24             # You should have received a copy of the GNU Lesser General Public
25             # License along with this library; if not, write to the Free Software
26             # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27             #
28              
29 2     2   1620 use English;
  2         9669  
  2         12  
30 2     2   1035 use Cwd 'abs_path';
  2         4  
  2         85  
31 2     2   1169 use ORM::Meta::ORM::History;
  2         4  
  2         2791  
32              
33             ##
34             ## CONSTRUCTORS
35             ##
36              
37             ## use: $hist = $history_class->new
38             ## (
39             ## obj => ORM,
40             ## changed => { $prop1_name => [ $old_value, $new_value ], ... },
41             ## error => ORM::Error,
42             ## );
43             ##
44             ## use: $hist = $history_class->new
45             ## (
46             ## obj => ORM,
47             ## created => 1,
48             ## error => ORM::Error,
49             ## );
50             ##
51             ## use: $hist = $history_class->new
52             ## (
53             ## obj => ORM,
54             ## deleted => 1,
55             ## error => ORM::Error,
56             ## );
57             ##
58             sub new
59             {
60 9     9 1 185 my $class = shift;
61 9         41 my %arg = @_;
62 9 50       38 my %prop = defined $arg{prop} ? %{$arg{prop}} : ();
  0         0  
63 9         41 my $error = ORM::Error->new;
64 9         24 my @record;
65              
66             # Define common properties
67 9         31 delete $arg{prop};
68              
69 9         35 $prop{obj_class} = ref $arg{obj};
70 9         55 $prop{obj_id} = $arg{obj}->id;
71 9         26 $prop{date} = time;
72              
73 9 50       42 if( $::ENV{REQUEST_URI} )
74             {
75 0         0 $prop{editor} =
76             "WWW: " .
77             $::ENV{REMOTE_USER} . '@' . $::ENV{SERVER_NAME} . ':' .
78             $::ENV{SERVER_PORT} . $::ENV{REQUEST_URI} .
79             ", RemoteIP: " . $::ENV{REMOTE_ADDR};
80             }
81             else
82             {
83 9         18 my $exec;
84 9 50       630 $exec = abs_path( $0 ) unless( $OSNAME eq 'MSWin32' );
85 9         196 $prop{editor} = "Exec[$PID]: $exec, UID: ${UID}:".(int $GID).", EUID: ${EUID}:".(int $EGID);
86             }
87              
88             # Define operation related properties and create objects
89 9 100       48 if( $arg{created} )
    100          
90             {
91 2         4 $prop{slaved_by} = undef;
92 2         5 $prop{prop_name} = 'id';
93 2         4 $prop{old_value} = undef;
94 2         8 $prop{new_value} = $arg{obj}->id;
95 2         19 push @record, $class->SUPER::new( prop=>\%prop, error=>$error );
96             }
97             elsif( $arg{deleted} )
98             {
99 2         8 $prop{slaved_by} = undef;
100 2         6 $prop{prop_name} = 'id';
101 2         11 $prop{old_value} = $arg{obj}->id;
102 2         8 $prop{new_value} = undef;
103 2         14 $prop{slaved_by} = $class->SUPER::new( prop=>\%prop, error=>$error );
104 2         8 push @record, $prop{slaved_by};
105              
106 2         14 for my $prop ( (ref $arg{obj})->_not_mandatory_props )
107             {
108 8 50       59 if( $error->fatal )
109             {
110 0         0 last;
111             }
112             else
113             {
114 8         22 $prop{prop_name} = $prop;
115 8         36 $prop{old_value} = $arg{obj}{_ORM_data}{$prop};
116 8         17 $prop{new_value} = undef;
117 8         45 push @record, $class->SUPER::new( prop=>\%prop, error=>$error );
118             }
119             }
120             }
121             else
122             {
123 5         17 $prop{slaved_by} = undef;
124 5         9 for my $prop ( keys %{$arg{changed}} )
  5         27  
125             {
126 7         15 my $record;
127 7 50       30 if( $error->fatal )
128             {
129 0         0 last;
130             }
131             else
132             {
133 7         21 $prop{prop_name} = $prop;
134 7         63 $prop{old_value} = $arg{changed}{$prop}[0];
135 7         26 $prop{new_value} = $arg{changed}{$prop}[1];
136              
137 7         51 $record = $class->SUPER::new( prop=>\%prop, %arg );
138 7 100       49 $prop{slaved_by} = $record unless( $prop{slaved_by} );
139 7         38 push @record, $record;
140             }
141             }
142             }
143              
144             # Rollback creation of history object if error occured
145 9 50       40 if( $error->fatal )
146             {
147 0         0 while( my $record = pop @record )
148             {
149 0 0       0 $record->SUPER::delete( error=>$error ) if( defined $record );
150             }
151             }
152              
153 9         41 $error->upto( $arg{error} );
154 9         264 return $record[0];
155             }
156              
157             ##
158             ## PROPERTIES
159             ##
160              
161             sub obj
162             {
163 0     0 0   my $self = shift;
164              
165 0 0         unless( $self->{obj} )
166             {
167 0           $self->_load_ORM_class( $self->obj_class );
168 0           $self->{obj} = $self->obj_class->find_id( id=>$self->obj_id );
169             }
170              
171 0           return $self->{obj};
172             }
173              
174 0     0 0   sub master { ! $_[0]->slaved_by; }
175              
176             ##
177             ## METHODS
178             ##
179              
180             sub update
181             {
182 0     0 1   my $self = shift;
183 0           my %arg = @_;
184              
185 0 0         $arg{error} && $arg{error}->add_fatal( "Updates of history have no sense" );
186             }
187              
188             sub delete
189             {
190 0     0 1   my $self = shift;
191 0           my $class = ref $self;
192              
193 0 0         if( $self->slaved_by )
194             {
195 0           $arg{error}->add_fatal( "You should not delete slaved objects, delete master instead" );
196             }
197             else
198             {
199 0           my @slave = $class->find
200             (
201             filter => ( $class->M->slaved_by == $self ),
202             error => $error,
203             );
204 0           for my $slave ( @slave )
205             {
206 0           $slave->delete( @_ );
207             }
208 0           $self->SUPER::delete( @_ );
209             }
210             }
211              
212             sub rollback
213             {
214 0     0 0   my $self = shift;
215 0           my $class = ref $self;
216 0           my %arg = @_;
217              
218 0 0         if( $self->slaved_by )
219             {
220 0           $arg{error}->add_fatal
221             (
222             "You should not rollback slaved object, rollback its master instead"
223             );
224             }
225             else
226             {
227 0           my $error = ORM::Error->new;
228 0           my $obj;
229             my @slave;
230              
231             # Case of created object
232 0 0 0       if( $self->prop_name eq 'id' && $self->old_value == undef )
    0 0        
233             {
234 0           $obj = $self->obj_class->find_id( id=>$self->obj_id, error=>$error );
235 0 0         if( $obj )
236             {
237 0           $obj->delete( error=>$error, history=>0 );
238             }
239             else
240             {
241 0           $error->add_fatal
242             (
243             "Can't rollback creation of object #" . $self->obj_id
244             . " of class '".$self->obj_class."' because it doesn't exist"
245             );
246             }
247             }
248             # Case of deleted object
249             elsif( $self->prop_name eq 'id' && $self->new_value == undef )
250             {
251 0           @slave = $class->find
252             (
253             filter => ( $class->M->slaved_by == $self ),
254             error => $error,
255             );
256 0 0         unless( $error->fatal )
257             {
258 0           my %prop;
259 0           for my $slave ( @slave )
260             {
261 0           $prop{$slave->prop_name} = $slave->old_value;
262             }
263 0           $obj = $self->obj_class->new
264             (
265             prop => \%prop,
266             repair_id => $self->old_value,
267             error => $error,
268             history => 0,
269             );
270             }
271             }
272             # Case of changed object
273             else
274             {
275 0           $obj = $self->obj_class->find_id( id=>$self->obj_id, error=>$error );
276 0 0         if( $obj )
277             {
278 0           @slave = $class->find
279             (
280             filter => ( $class->M->slaved_by == $self ),
281             error => $error,
282             );
283 0 0         unless( $error->fatal )
284             {
285 0           my %prop;
286             my %old_prop;
287 0           for my $slave ( $self, @slave )
288             {
289 0           $prop{$slave->prop_name} = $slave->old_value;
290 0           $old_prop{$slave->prop_name} = $slave->new_value;
291             }
292             $obj->update
293             (
294 0           prop => \%prop,
295             old_prop => \%old_prop,
296             error => $error,
297             history => 0,
298             );
299             }
300             }
301             else
302             {
303 0           $error->add_fatal
304             (
305             "Can't rollback update of object #" . $self->obj_id
306             . " of class '".$self->obj_class."' because it doesn't exist"
307             );
308             }
309             }
310              
311 0 0         unless( $error->fatal )
312             {
313 0           $self->delete( error=>$error );
314             }
315              
316 0           $error->upto( $arg{error} );
317             }
318             }
319              
320 0     0 0   sub metaprop_class { 'ORM::Meta::ORM::History'; }