File Coverage

blib/lib/Rose/Planter/Soil.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package Rose::Planter::Soil;
2              
3             =head1 NAME
4              
5             Rose::Planter::Soil -- default base object class for classes created by Rose::Planter.
6              
7             =head1 DESCRIPTION
8              
9             This provides a few extra handy functions and
10             defaults for manipulating Rose classes.
11              
12             =head1 METHODS
13              
14             =cut
15              
16 1     1   5868 use strict;
  1         2  
  1         33  
17 1     1   5 use warnings;
  1         1  
  1         30  
18              
19 1     1   4 use Log::Log4perl qw/:easy/;
  1         2  
  1         6  
20 1     1   638 use base 'Rose::DB::Object';
  1         2  
  1         539  
21 1     1   4571 use Rose::DB::Object::Helpers qw/:all/;
  0            
  0            
22              
23             =head2 as_hash
24              
25             Like Rose::DB::Object::Helper::as_tree but with a few differences :
26              
27             - parent keys in a child table are excluded.
28              
29             - datetimes are returned in ISO 8601 format.
30              
31             - the parameter skip_re can be given to skip columns matching a regex.
32              
33             - only one-to-one and one-to-many relationships are traversed
34              
35             =cut
36              
37             sub as_hash {
38             my $self = shift;
39             my %args = @_;
40             my $skip_re = $args{skip_re};
41             my $parent = $args{_parent};
42             my %parent_columns;
43              
44             if ($parent) {
45             %parent_columns = reverse $parent->column_map;
46             }
47              
48             my %h; # to be returned.
49              
50             for my $col ( $self->meta->columns ) {
51             next if $parent_columns{$col->name};
52             my $accessor = $col->accessor_method_name;
53             my $value = scalar( $self->$accessor );
54             if (ref $value eq 'DateTime') {
55             # timezone may be a DateTime::TimeZone::OffsetOnly
56             # whose name is e.g. -0400. It needs to be -04:00 for iso 8601.
57             my $offset = $value->time_zone->name;
58             $value = $value->iso8601;
59             if ($offset =~ /\d{4}/ ) {
60             $offset=~ s/00$/:00/;
61             $value .= $offset;
62             } elsif ($offset =~ /^UTC|floating/) {
63             # ok
64             } else {
65             # Could this happen with an explicitly set timezone?
66             WARN "unrecognized timezone name : $offset";
67             }
68             }
69             next if $skip_re && $accessor =~ /$skip_re/;
70             $h{$accessor} = $value;
71             }
72              
73             for my $rel ($self->meta->relationships) {
74             next unless $rel->object_has_related_objects($self); # undocumented API call
75             my $name = $rel->name;
76             die "cannot recurse" unless $self->can($name);
77             if ($rel->type eq 'one to one') {
78             $h{$name} = $self->$name->as_hash( _parent => $rel);
79             } elsif ($rel->type eq 'one to many') {
80             my @children = $self->$name;
81             for my $child (@children) {
82             die "cannot dump $name" unless $child->can('as_hash');
83             $h{$name} ||= [];
84             push @{ $h{$name} }, $child->as_hash( _parent => $rel);
85             }
86             } else {
87             # warn "relationship type ".$rel->type." not implemented in as_hash";
88             # silently skip many-to-one relationships
89             }
90             }
91              
92             return \%h;
93             }
94              
95             =head2 nested_tables
96              
97             Get or set a list of "nested table" associated with this
98             class. These are tables which are always retrieved alongside
99             this one.
100              
101             =cut
102              
103             our %NestedMap;
104             sub nested_tables {
105             # The Right way to do this is probably to provide our own base meta class, too.
106             my $self = shift;
107             my $class = ref $self || $self;
108             return $NestedMap{$class} unless @_ > 0;
109             $NestedMap{$class} = ref($_[0]) ? shift : [ @_ ];
110             return $NestedMap{$class};
111             }
112              
113             1;
114