| 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 |