File Coverage

blib/lib/SPOPS.pm
Criterion Covered Total %
statement 19 21 90.4
branch n/a
condition n/a
subroutine 7 7 100.0
pod n/a
total 26 28 92.8


line stmt bran cond sub pod time code
1             package SPOPS;
2              
3             # $Id: SPOPS.pm,v 3.39 2004/06/02 00:48:20 lachoy Exp $
4              
5 17     17   107 use strict;
  17         77  
  17         714  
6 17     17   99 use base qw( Exporter ); # Class::Observable
  17         34  
  17         2184  
7 17     17   22590 use Data::Dumper qw( Dumper );
  17         126579  
  17         1680  
8 17     17   187 use Log::Log4perl qw( get_logger );
  17         45  
  17         175  
9 17     17   16916 use SPOPS::ClassFactory::DefaultBehavior;
  17         72  
  17         766  
10 17     17   132 use SPOPS::Exception;
  17         34  
  17         172  
11 17     17   24653 use SPOPS::Tie qw( IDX_CHANGE IDX_SAVE IDX_CHECK_FIELDS IDX_LAZY_LOADED );
  0            
  0            
12             use SPOPS::Tie::StrictField;
13             use SPOPS::Secure qw( SEC_LEVEL_WRITE );
14              
15             my $log = get_logger();
16              
17             $SPOPS::AUTOLOAD = '';
18             $SPOPS::VERSION = '0.87';
19             $SPOPS::Revision = sprintf("%d.%02d", q$Revision: 3.39 $ =~ /(\d+)\.(\d+)/);
20              
21             # DEPRECATED
22              
23             sub DEBUG { return 1 }
24             sub set_global_debug { warn "Global debugging not supported -- use log4perl instead!\n" }
25              
26             my ( $USE_CACHE );
27             sub USE_CACHE { return $USE_CACHE }
28             sub set_global_use_cache { $USE_CACHE = $_[1] }
29              
30             @SPOPS::EXPORT_OK = qw( _w _wm DEBUG );
31              
32             require SPOPS::Utility;
33              
34             ########################################
35             # CLASS CONFIGURATION
36             ########################################
37              
38             # These are default configuration behaviors -- all SPOPS classes have
39             # the option of using them or of halting behavior before they're
40             # called
41              
42             sub behavior_factory {
43             my ( $class ) = @_;
44              
45             $log->is_info &&
46             $log->info( "Installing SPOPS default behaviors for ($class)" );
47             return { manipulate_configuration =>
48             \&SPOPS::ClassFactory::DefaultBehavior::conf_modify_config,
49             read_code =>
50             \&SPOPS::ClassFactory::DefaultBehavior::conf_read_code,
51             id_method =>
52             \&SPOPS::ClassFactory::DefaultBehavior::conf_id_method,
53             has_a =>
54             \&SPOPS::ClassFactory::DefaultBehavior::conf_relate_hasa,
55             fetch_by =>
56             \&SPOPS::ClassFactory::DefaultBehavior::conf_relate_fetchby,
57             add_rule =>
58             \&SPOPS::ClassFactory::DefaultBehavior::conf_add_rules, };
59             }
60              
61              
62             ########################################
63             # CLASS INITIALIZATION
64             ########################################
65              
66             # Subclasses should almost certainly define some behavior here by
67             # overriding this method
68              
69             sub class_initialize {}
70              
71              
72             ########################################
73             # OBJECT CREATION/DESTRUCTION
74             ########################################
75              
76             # Constructor
77              
78             sub new {
79             my ( $pkg, $p ) = @_;
80             my $class = ref $pkg || $pkg;
81             my $params = {};
82             my $tie_class = 'SPOPS::Tie';
83              
84             my $CONFIG = $class->CONFIG;
85              
86             # Setup field checking if specified
87              
88             if ( $CONFIG->{strict_field} || $p->{strict_field} ) {
89             my $fields = $class->field;
90             if ( keys %{ $fields } ) {
91             $params->{field} = [ keys %{ $fields } ];
92             $tie_class = 'SPOPS::Tie::StrictField'
93             }
94             }
95              
96             # Setup lazy loading if specified
97              
98             if ( ref $CONFIG->{column_group} eq 'HASH' and
99             keys %{ $CONFIG->{column_group} } ) {
100             $params->{is_lazy_load} = 1;
101             $params->{lazy_load_sub} = $class->get_lazy_load_sub;
102             }
103              
104             # Setup field mapping if specified
105              
106             if ( ref $CONFIG->{field_map} eq 'HASH' and
107             scalar keys %{ $CONFIG->{field_map} } ) {
108             $params->{is_field_map} = 1;
109             $params->{field_map} = \%{ $CONFIG->{field_map} };
110             }
111              
112             # Setup multivalue fields if specified
113              
114             my $multivalue_ref = ref $CONFIG->{multivalue};
115             if ( $multivalue_ref eq 'HASH' or $multivalue_ref eq 'ARRAY' ) {
116             my $num = ( $multivalue_ref eq 'HASH' )
117             ? scalar keys %{ $CONFIG->{multivalue} }
118             : scalar @{ $CONFIG->{multivalue} };
119             if ( $num > 0 ) {
120             $params->{is_multivalue} = 1;
121             $params->{multivalue} = ( $multivalue_ref eq 'HASH' )
122             ? \%{ $CONFIG->{multivalue} }
123             : \@{ $CONFIG->{multivalue} };
124             }
125             }
126              
127             $params->{is_lazy_load} ||= 0;
128             $params->{is_field_map} ||= 0;
129              
130             $log->is_info &&
131             $log->info( "Creating new object of class ($class) with tie class ",
132             "($tie_class); lazy loading ($params->{is_lazy_load});",
133             "field mapping ($params->{is_field_map})" );
134              
135             my ( %data );
136             my $internal = tie %data, $tie_class, $class, $params;
137             $log->is_debug &&
138             $log->debug( "Internal tie structure of new object: ", Dumper( $internal ) );
139             my $self = bless( \%data, $class );
140              
141             # Set defaults if set, unless NOT specified
142              
143             my $defaults = $p->{default_values} || $CONFIG->{default_values};
144             if ( ref $defaults eq 'HASH' and ! $p->{skip_default_values} ) {
145             foreach my $field ( keys %{ $defaults } ) {
146             if ( ref $defaults->{ $field } eq 'HASH' ) {
147             my $default_class = $defaults->{ $field }{class};
148             my $default_method = $defaults->{ $field }{method};
149             unless ( $default_class and $default_method ) {
150             $log->warn( "Cannot set default for ($field) without a class ",
151             "AND method being defined." );
152             next;
153             }
154             $self->{ $field } = eval { $default_class->$default_method( $field ) };
155             if ( $@ ) {
156             $log->warn( "Cannot set default for ($field) in ($class) using",
157             "($default_class) ($default_method): $@" );
158             }
159             }
160             elsif ( $defaults->{ $field } eq 'NOW' ) {
161             $self->{ $field } = SPOPS::Utility->now;
162             }
163             else {
164             $self->{ $field } = $defaults->{ $field };
165             }
166             }
167             }
168              
169             $self->initialize( $p );
170             $self->has_change;
171             $self->clear_save;
172             $self->initialize_custom( $p );
173             return $self;
174             }
175              
176              
177             sub DESTROY {
178             my ( $self ) = @_;
179              
180             # Need to check that $log exists because sometimes it gets
181             # destroyed before our SPOPS objects do
182              
183             if ( $log ) {
184             $log->is_debug &&
185             $log->debug( "Destroying SPOPS object '", ref( $self ), "' ID: " .
186             "'", $self->id, "' at time: ", scalar localtime );
187             }
188             }
189              
190              
191             # Create a new object from an old one, allowing any passed-in
192             # values to override the ones from the old object
193              
194             sub clone {
195             my ( $self, $p ) = @_;
196             my $class = $p->{_class} || ref $self;
197             $log->is_info &&
198             $log->info( "Cloning new object of class '$class' from old ",
199             "object of class '", ref( $self ), "'" );
200             my %initial_data = ();
201              
202             my $id_field = $class->id_field;
203             if ( $id_field ) {
204             $initial_data{ $id_field } = $p->{ $id_field } || $p->{id};
205             }
206              
207             my $fields = $self->_get_definitive_fields;
208             foreach my $field ( @{ $fields } ) {
209             next if ( $id_field and $field eq $id_field );
210             $initial_data{ $field } =
211             exists $p->{ $field } ? $p->{ $field } : $self->{ $field };
212             }
213              
214             return $class->new({ %initial_data, skip_default_values => 1 });
215             }
216              
217              
218             # Simple initialization: subclasses can override for
219             # field validation or whatever.
220              
221             sub initialize {
222             my ( $self, $p ) = @_;
223             $p ||= {};
224              
225             # Creating a new object, all fields are set to 'loaded' so we don't
226             # try to lazy-load a field when the object hasn't even been saved
227              
228             $self->set_all_loaded();
229              
230             # We allow the user to substitute id => value instead for the
231             # specific fieldname.
232              
233             $self->id( $p->{id} ) if ( $p->{id} );
234             #$p->{ $self->id_field } ||= $p->{id};
235              
236             # Go through the data passed in and set data for fields used by
237             # this class
238              
239             my $class_fields = $self->field || {};
240             while ( my ( $field, $value ) = each %{ $p } ) {
241             next unless ( $class_fields->{ $field } );
242             $self->{ $field } = $value;
243             }
244             }
245              
246             # subclasses can override...
247             sub initialize_custom { return }
248              
249             ########################################
250             # CONFIGURATION
251             ########################################
252              
253             # If a class doesn't define a config method then something is seriously wrong
254              
255             sub CONFIG {
256             require Carp;
257             Carp::croak "SPOPS class not created properly, since CONFIG being called ",
258             "from SPOPS.pm rather than your object class.";
259             }
260              
261              
262             # Some default configuration methods that all SPOPS classes use
263              
264             sub field { return $_[0]->CONFIG->{field} || {} }
265             sub field_list { return $_[0]->CONFIG->{field_list} || [] }
266             sub field_raw { return $_[0]->CONFIG->{field_raw} || [] }
267             sub field_all_map {
268             return { map { $_ => 1 } ( @{ $_[0]->field_list }, @{ $_[0]->field_raw } ) }
269             }
270             sub id_field { return $_[0]->CONFIG->{id_field} }
271             sub creation_security { return $_[0]->CONFIG->{creation_security} || {} }
272             sub no_security { return $_[0]->CONFIG->{no_security} }
273              
274             # if 'field_raw' defined use that, otherwise just return 'field_list'
275              
276             sub _get_definitive_fields {
277             my ( $self ) = @_;
278             my $fields = $self->field_raw;
279             unless ( ref $fields eq 'ARRAY' and scalar @{ $fields } > 0 ) {
280             $fields = $self->field_list;
281             }
282             return $fields;
283             }
284              
285             ########################################
286             # STORABLE SERIALIZATION
287              
288             sub store {
289             my ( $self, @params ) = @_;
290             die "Not an object!" unless ( ref $self and $self->isa( 'SPOPS' ) );
291             require Storable;
292             return Storable::store( $self, @params );
293             }
294              
295             sub nstore {
296             my ( $self, @params ) = @_;
297             die "Not an object!" unless ( ref $self and $self->isa( 'SPOPS' ) );
298             require Storable;
299             return Storable::nstore( $self, @params );
300             }
301              
302             sub retrieve {
303             my ( $class, @params ) = @_;
304             require Storable;
305             return Storable::retrieve( @params );
306             }
307              
308             sub fd_retrieve {
309             my ( $class, @params ) = @_;
310             require Storable;
311             return Storable::fd_retrieve( @params );
312             }
313              
314              
315             ########################################
316             # RULESET METHODS
317             ########################################
318              
319             # So all SPOPS classes have a ruleset_add in their lineage
320              
321             sub ruleset_add { return __PACKAGE__ }
322             sub ruleset_factory {}
323              
324             # These are actions to do before/after a fetch, save and remove; note
325             # that overridden methods must return a 1 on success or the
326             # fetch/save/remove will fail; this allows any of a number of rules to
327             # short-circuit an operation; see RULESETS in POD
328             #
329             # clarification: $_[0] in the following can be *either* a class or an
330             # object; $_[1] is the (optional) hashref passed as the only argument
331              
332             sub pre_fetch_action { return $_[0]->ruleset_process_action( 'pre_fetch_action', $_[1] ) }
333             sub post_fetch_action { return $_[0]->ruleset_process_action( 'post_fetch_action', $_[1] ) }
334             sub pre_save_action { return $_[0]->ruleset_process_action( 'pre_save_action', $_[1] ) }
335             sub post_save_action { return $_[0]->ruleset_process_action( 'post_save_action', $_[1] ) }
336             sub pre_remove_action { return $_[0]->ruleset_process_action( 'pre_remove_action', $_[1] ) }
337             sub post_remove_action { return $_[0]->ruleset_process_action( 'post_remove_action', $_[1] ) }
338              
339             #sub pre_fetch_action { return shift->notify_observers( 'pre_fetch_action', @_ ) }
340             #sub post_fetch_action { return shift->notify_observers( 'post_fetch_action', @_ ) }
341             #sub pre_save_action { return shift->notify_observers( 'pre_save_action', @_ ) }
342             #sub post_save_action { return shift->notify_observers( 'post_save_action', @_ ) }
343             #sub pre_remove_action { return shift->notify_observers( 'pre_remove_action', @_ ) }
344             #sub post_remove_action { return shift->notify_observers( 'post_remove_action', @_ ) }
345              
346             # Go through all of the subroutines found in a particular class
347             # relating to a particular action
348              
349             sub ruleset_process_action {
350             my ( $item, $action, $p ) = @_;
351             #die "This method is no longer used. Please see SPOPS::Manual::ObjectRules.\n";
352              
353             my $class = ref $item || $item;
354              
355             $action = lc $action;
356             $log->is_info &&
357             $log->info( "Trying to process $action for a '$class' object" );
358              
359             # Grab the ruleset table for this class and immediately
360             # return if the list of rules to apply for this action is empty
361              
362             my $rs_table = $item->RULESET;
363             unless ( ref $rs_table->{ $action } eq 'ARRAY'
364             and scalar @{ $rs_table->{ $action } } > 0 ) {
365             $log->is_debug &&
366             $log->debug( "No rules to process for [$action]" );
367             return 1;
368             }
369             $log->is_info &&
370             $log->info( "Ruleset exists in class." );
371              
372             # Cycle through the rules -- the only return value can be true or false,
373             # and false short-circuits the entire operation
374              
375             my $count_rules = 0;
376             foreach my $rule_sub ( @{ $rs_table->{ $action } } ) {
377             $count_rules++;
378             unless ( $rule_sub->( $item, $p ) ) {
379             $log->warn( "Rule $count_rules of '$action' for class '$class' failed" );
380             return undef;
381             }
382             }
383             $log->is_info &&
384             $log->info( "$action processed ($count_rules rules successful) without error" );
385             return 1;
386             }
387              
388              
389             ########################################
390             # SERIALIZATION
391             ########################################
392              
393             # Routines for subclases to override
394              
395             sub save { die "Subclass must implement save()\n" }
396             sub fetch { die "Subclass must implement fetch()\n" }
397             sub remove { die "Subclass must implement remove()\n" }
398             sub log_action { return 1 }
399              
400             # Define methods for implementors to override to do something in case
401             # a fetch / save / remove fails
402              
403             sub fail_fetch {}
404             sub fail_save {}
405             sub fail_remove {}
406              
407              
408             ########################################
409             # SERIALIZATION SUPPORT
410             ########################################
411              
412             sub fetch_determine_limit { return SPOPS::Utility->determine_limit( $_[1] ) }
413              
414              
415             ########################################
416             # LAZY LOADING
417             ########################################
418              
419             sub get_lazy_load_sub { return \&perform_lazy_load }
420             sub perform_lazy_load { return undef }
421              
422             sub is_loaded { return tied( %{ $_[0] } )->{ IDX_LAZY_LOADED() }{ lc $_[1] } }
423              
424             sub set_loaded { return tied( %{ $_[0] } )->{ IDX_LAZY_LOADED() }{ lc $_[1] }++ }
425              
426             sub set_all_loaded {
427             my ( $self ) = @_;
428             $log->is_info &&
429             $log->info( "Setting all fields to loaded for object class", ref $self );
430             $self->set_loaded( $_ ) for ( @{ $self->field_list } );
431             }
432              
433             sub clear_loaded { tied( %{ $_[0] } )->{ IDX_LAZY_LOADED() }{ lc $_[1] } = undef }
434              
435             sub clear_all_loaded {
436             $log->is_info &&
437             $log->info( "Clearing all fields to unloaded for object class", ref $_[0] );
438             tied( %{ $_[0] } )->{ IDX_LAZY_LOADED() } = {};
439             }
440              
441              
442             ########################################
443             # FIELD CHECKING
444             ########################################
445              
446             # Is this object doing field checking?
447              
448             sub is_checking_fields { return tied( %{ $_[0] } )->{ IDX_CHECK_FIELDS() }; }
449              
450              
451             ########################################
452             # MODIFICATION STATE
453             ########################################
454              
455             # Track whether this object has changed (keep 'changed()' for backward
456             # compatibility)
457              
458             sub changed { is_changed( @_ ) }
459             sub is_changed { return $_[0]->{ IDX_CHANGE() } }
460             sub has_change { $_[0]->{ IDX_CHANGE() } = 1 }
461             sub clear_change { $_[0]->{ IDX_CHANGE() } = 0 }
462              
463              
464             ########################################
465             # SERIALIZATION STATE
466             ########################################
467              
468             # Track whether this object has been saved (keep 'saved()' for
469             # backward compatibility)
470              
471             sub saved { is_saved( @_ ) }
472             sub is_saved { return $_[0]->{ IDX_SAVE() } }
473             sub has_save { $_[0]->{ IDX_SAVE() } = 1 }
474             sub clear_save { $_[0]->{ IDX_SAVE() } = 0 }
475              
476              
477             ########################################
478             # OBJECT INFORMATION
479             ########################################
480              
481             # Return the name of this object (what type it is), title of the
482             # object and url (in a hashref) to be used to make a link, or whatnot.
483              
484             sub object_description {
485             my ( $self ) = @_;
486             my $object_type = $self->CONFIG->{object_name};
487             my $title_info = $self->CONFIG->{name};
488             my $title = '';
489             if ( ref $title_info eq 'CODE' ) {
490             warn "NOTE: Setting a coderef for the 'name' configuration ",
491             "key in [$object_type] is deprecated. It will be phased ",
492             "out.\n";
493             $title = eval { $title_info->( $self ) };
494             }
495             elsif ( exists $self->{ $title_info } ) {
496             $title = $self->{ $title_info };
497             }
498             else {
499             $title = eval { $self->$title_info() };
500             }
501             $title ||= 'Cannot find name';
502             my $oid = $self->id;
503             my $id_field = $self->id_field;
504             my $link_info = $self->CONFIG->{display};
505             my ( $url, $url_edit );
506             if ( $link_info->{url} ) {
507             $url = "$link_info->{url}?" . $id_field . '=' . $oid;
508             }
509             if ( $link_info->{url_edit} ) {
510             $url_edit = "$link_info->{url_edit}?" . $id_field . '=' . $oid;
511             }
512             else {
513             $url_edit = "$link_info->{url}?edit=1;" . $id_field . '=' . $oid;
514             }
515             return { class => ref $self,
516             object_id => $oid,
517             oid => $oid,
518             id_field => $id_field,
519             name => $object_type,
520             title => $title,
521             security => $self->{tmp_security_level},
522             url => $url,
523             url_edit => $url_edit };
524             }
525              
526              
527             # This is very primitive, but objects that want something more
528             # fancy/complicated can implement it for themselves
529              
530             sub as_string {
531             my ( $self ) = @_;
532             my $msg = '';
533             my $fields = $self->CONFIG->{as_string_order} || $self->field_list;
534             my $labels = $self->CONFIG->{as_string_label} || { map { $_ => $_ } @{ $fields } };
535             foreach my $field ( @{ $fields } ) {
536             $msg .= sprintf( "%-20s: %s\n", $labels->{ $field }, $self->{ $field } );
537             }
538             return $msg;
539             }
540              
541              
542             # This is even more primitive, but again, we're just providing the
543             # basics :-)
544              
545             sub as_html {
546             my ( $self ) = @_;
547             return "
" . $self->as_string . "\n
\n";
548             }
549              
550              
551             ########################################
552             # SECURITY
553             ########################################
554              
555             # These are the default methods that classes not using security
556             # inherit. Default action is WRITE, so everything is allowed
557              
558             sub check_security { return SEC_LEVEL_WRITE }
559             sub check_action_security { return SEC_LEVEL_WRITE }
560             sub create_initial_security { return 1 }
561              
562              
563             ########################################
564             # CACHING
565             ########################################
566              
567             # NOTE: CACHING IS NOT FUNCTIONAL AND THESE MAY RADICALLY CHANGE
568              
569             # All objects are by default cached; set the key 'no_cache'
570             # to a true value to *not* cache this object
571              
572             sub no_cache { return $_[0]->CONFIG->{no_cache} || 0 }
573              
574             # Your class should determine how to get to the cache -- the normal
575             # way is to have all your objects inherit from a common base class
576             # which deals with caching, datasource handling, etc.
577              
578             sub global_cache { return undef }
579              
580             # Actions to do before/after retrieving/saving/removing
581             # an item from the cache
582              
583             sub pre_cache_fetch { return 1 }
584             sub post_cache_fetch { return 1 }
585             sub pre_cache_save { return 1 }
586             sub post_cache_save { return 1 }
587             sub pre_cache_remove { return 1 }
588             sub post_cache_remove { return 1 }
589              
590              
591             sub get_cached_object {
592             my ( $class, $p ) = @_;
593             return undef unless ( $p->{id} );
594             return undef unless ( $class->use_cache( $p ) );
595              
596             # If we can retrieve an item from the cache, then create a new object
597             # and assign the values from the cache to it.
598             my $item_data = $class->global_cache->get({ class => $class,
599             object_id => $p->{id} });
600             if ( $item_data ) {
601             $log->is_info &&
602             $log->info( "Retrieving from cache..." );
603             return $class->new( $item_data );
604             }
605             $log->is_info &&
606             $log->info( "Cached data not found." );
607             return undef;
608             }
609              
610              
611             sub set_cached_object {
612             my ( $self, $p ) = @_;
613             return undef unless ( ref $self );
614             return undef unless ( $self->id );
615             return undef unless ( $self->use_cache( $p ) );
616             return $self->global_cache->set({ data => $self });
617             }
618              
619              
620             # Return 1 if we're using the cache; undef if not -- right now we
621             # always return undef since caching isn't enabled
622              
623             sub use_cache {
624             return undef unless ( $USE_CACHE );
625             my ( $class, $p ) = @_;
626             return undef if ( $p->{skip_cache} );
627             return undef if ( $class->no_cache );
628             return undef unless ( $class->global_cache );
629             return 1;
630             }
631              
632              
633             ########################################
634             # ACCESSORS/MUTATORS
635             ########################################
636              
637             # We should probably deprecate these...
638              
639             sub get { return $_[0]->{ $_[1] } }
640             sub set { return $_[0]->{ $_[1] } = $_[2] }
641              
642              
643             # return a simple hashref of this object's data -- not tied, not as an
644             # object
645              
646             sub as_data_only {
647             my ( $self ) = @_;
648             my $fields = $self->_get_definitive_fields;
649             return { map { $_ => $self->{ $_ } } grep ! /^(tmp|_)/, @{ $fields } };
650             }
651              
652             # Backward compatible...
653              
654             sub data { return as_data_only( @_ ) }
655              
656             sub AUTOLOAD {
657             my ( $item, @params ) = @_;
658             my $request = $SPOPS::AUTOLOAD;
659             $request =~ s/.*://;
660              
661             # First, give a nice warning and return undef if $item is just a
662             # class rather than an object
663              
664             my $class = ref $item;
665             unless ( $class ) {
666             $log->warn( "Cannot fill class method '$request' from class '$item'" );
667             return undef;
668             }
669              
670             $log->is_info &&
671             $log->info( "AUTOLOAD caught '$request' from '$class'" );
672              
673             if ( ref $item and $item->is_checking_fields ) {
674             my $fields = $item->field_all_map || {};
675             my ( $field_name ) = $request =~ /^(\w+)_clear/;
676             if ( exists $fields->{ $request } ) {
677             $log->is_debug &&
678             $log->debug( "$class to fill param '$request'; returning data." );
679             # TODO: make these internal methods inheritable?
680             $item->_internal_create_field_methods( $class, $request );
681             return $item->$request( @params );
682             }
683             elsif ( $field_name and exists $fields->{ $field_name } ) {
684             $log->is_debug &&
685             $log->debug( "$class to fill param clear '$request'; ",
686             "creating '$field_name' methods" );
687             $item->_internal_create_field_methods( $class, $field_name );
688             return $item->$request( @params );
689             }
690             elsif ( my $value = $item->{ $request } ) {
691             $log->is_debug &&
692             $log->debug( " $request must be a temp or something, returning value." );
693             return $value;
694             }
695             elsif ( $request =~ /^tmp_/ ) {
696             $log->is_debug &&
697             $log->debug( "$request is a temp var, but no value saved. Returning undef." );
698             return undef;
699             }
700             elsif ( $request =~ /^_internal/ ) {
701             $log->is_debug &&
702             $log->debug( "$request is an internal request, but no value",
703             "saved. Returning undef." );
704             return undef;
705             }
706             $log->warn( "AUTOLOAD Error: Cannot access the method $request via <<$class>>",
707             "with the parameters ", join( ' ', @_ ) );
708             return undef;
709             }
710             my ( $field_name ) = $request =~ /^(\w+)_clear/;
711             if ( $field_name ) {
712             $log->is_debug &&
713             $log->debug( "$class is not checking fields, so create sub and return ",
714             "data for '$field_name'" );
715             $item->_internal_create_field_methods( $class, $field_name );
716             }
717             else {
718             $log->is_debug &&
719             $log->debug( "$class is not checking fields, so create sub and return ",
720             "data for '$request'" );
721             $item->_internal_create_field_methods( $class, $request );
722             }
723             return $item->$request( @params );
724             }
725              
726             sub _internal_create_field_methods {
727             my ( $item, $class, $field_name ) = @_;
728              
729             no strict 'refs';
730              
731             # First do the accessor/mutator...
732             *{ $class . '::' . $field_name } = sub {
733             my ( $self, $value ) = @_;
734             if ( defined $value ) {
735             $self->{ $field_name } = $value;
736             }
737             return $self->{ $field_name };
738             };
739              
740             # Now the mutator to clear the field value
741             *{ $class . '::' . $field_name . '_clear' } = sub {
742             my ( $self ) = @_;
743             delete $self->{ $field_name };
744             return undef;
745             };
746              
747             return;
748             }
749              
750              
751             ########################################
752             # DEBUGGING
753              
754             # DEPRECATED! Use log4perl instead!
755              
756             sub _w {
757             my $lev = shift || 0;
758             if ( $lev == 0 ) {
759             $log->warn( @_ );
760             }
761             elsif ( $lev == 1 ) {
762             $log->is_info &&
763             $log->info( @_ );
764             }
765             else {
766             $log->is_debug &&
767             $log->debug( @_ );
768             }
769             }
770              
771              
772             sub _wm {
773             my ( $lev, $check, @msg ) = @_;
774             return _w( $lev, @msg );
775             }
776              
777             1;
778              
779             __END__