File Coverage

blib/lib/Class/DBI/Loader/Relationship.pm
Criterion Covered Total %
statement 37 44 84.0
branch 11 18 61.1
condition 2 3 66.6
subroutine 6 6 100.0
pod 0 1 0.0
total 56 72 77.7


line stmt bran cond sub pod time code
1             package Class::DBI::Loader::Relationship;
2 1     1   746 use 5.006;
  1         4  
  1         32  
3 1     1   5 use strict;
  1         1  
  1         26  
4 1     1   19 use warnings;
  1         2  
  1         69  
5             our $VERSION = '1.2';
6             our $DEBUG = 0;
7              
8             1;
9              
10             =head1 NAME
11              
12             Class::DBI::Loader::Relationship - Easier relationship specification in CDBI::L
13              
14             =head1 SYNOPSIS
15              
16             use Class::DBI::Loader::Relationship;
17              
18             my $loader = Class::DBI::Loader->new( dsn => "mysql:beerdb",
19             namespace => "BeerDB");
20              
21             Now instead of saying
22              
23             BeerDB::Brewery->has_many(beers => "BeerDB::Beer");
24             BeerDB::Beer->has_a(brewery => "BeerDB::Brewery");
25              
26             BeerDB::Handpump->has_a(beer => "BeerDB::Beer");
27             BeerDB::Handpump->has_a(pub => "BeerDB::Pub");
28             BeerDB::Pub->has_many(beers => [ BeerDB::Handpump => 'beer' ]);
29             BeerDB::Beer->has_many(pubs => [ BeerDB::Handpump => 'pub' ]);
30              
31             Just say
32              
33             $loader->relationship( "a brewery produces beers" );
34             $loader->relationship( "a pub has beers on handpumps" );
35              
36             =head1 DESCRIPTION
37              
38             This module acts as a mix-in, adding the C method to
39             C. Since C knows how to map
40             between table names and class names, there ought to be no need to
41             replicate the names.
42              
43             In addition, it is common (but not universal) to want reverse relationships
44             defined for has-many relationships, and for has-a relationships to be
45             defined for the linkages surrounding a many-to-many table.
46              
47             The aim of C is to simplify the declaration of
48             common database relationships by providing both of these features.
49              
50             The C takes a string. It recognises table names (singular
51             or plural, for convenience) and extracts them from the "sentence".
52              
53             =cut
54              
55             package Class::DBI::Loader::Generic;
56 1     1   694 use Lingua::EN::Inflect::Number qw(PL to_PL to_S);
  1         567  
  1         6  
57 1     1   279 use Carp;
  1         3  
  1         674  
58              
59             sub relationship {
60 4     4 0 3934 my $self = shift;
61 4         8 my $text = shift;
62 4         20 my %tables = map { $_ => $_, PL($_) => $_ } $self->tables;
  16         8661  
63 66         103 my $table_re = join "|", map quotemeta,
64 4         818 sort { length $b <=> length $a } keys %tables;
65 4 50       224 croak "Couldn't understand the first object you were talking about"
66             unless $text =~ s/^((an?|the)\s+)?($table_re)\s*//i;
67 4         19 my $from = $tables{$3};
68 4         25 my $from_c = $self->find_class($from);
69 4         39 $text =~ s/^(might\s+)?\w+(\s+an?)?\s+//i;
70 4         8 my $method = "has_many";
71 4 100       18 $method = "has_a" if $2;
72 4 50       13 $method = "might_have" if $1;
73            
74 4 50       106 croak "Couldn't understand the second object you were talking about"
75             unless $text =~ s/.*?($table_re)\b//i;
76 4         10 my $to = $tables{$1};
77 4         12 my $to_c = $self->find_class($to);
78 4 100       67 my $mapper = $method eq "has_many" ? to_PL($to) : to_S($to);
79 4 100       4188 if ($text =~ /($table_re)/i) {
80 1         4 my $via = $tables{$1}; my $via_c = $self->find_class($via);
  1         4  
81 1 50       13 return "$via_c->has_a(".to_S($from)." => $from_c)\n".
82             "$via_c->has_a(".to_S($to)." => $to_c)\n".
83             "$from_c->$method($mapper => [ $via_c => ".to_S($to)." ])\n".
84             "$to_c->has_many(".to_PL($from)." => [ $via_c => ".to_S($from)." ])\n"
85             if $DEBUG;
86              
87 0         0 $via_c->has_a(to_S($from) => $from_c);
88 0         0 $via_c->has_a(to_S($to) => $to_c);
89 0         0 $from_c->$method($mapper => [ $via_c => to_S($to) ]);
90 0         0 $to_c->has_many(to_PL($from) => [ $via_c => to_S($from) ]);
91 0         0 return;
92             }
93 3 50 66     43 return "$from_c->$method($mapper => $to_c);\n".
94             ($method ne "has_a" && "$to_c->has_a(".to_S($from)." => $from_c);\n")
95             if $DEBUG;
96 0           $from_c->$method($mapper => $to_c);
97 0 0         $to_c->has_a(to_S($from) => $from_c) unless $method eq "has_a";
98             }
99              
100             1;
101              
102             =head1 AUTHOR
103              
104             Simon Cozens, C
105              
106             =head1 SEE ALSO
107              
108             L.
109              
110             =cut