File: JoinTable.pm

package info (click to toggle)
libdbix-class-helpers-perl 2.013002-1
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 420 kB
  • sloc: perl: 1,931; sql: 73; makefile: 2
file content (354 lines) | stat: -rw-r--r-- 8,912 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
package DBIx::Class::Helper::Row::JoinTable;
{
  $DBIx::Class::Helper::Row::JoinTable::VERSION = '2.013002';
}

use strict;
use warnings;

# ABSTRACT: Easily set up join tables with DBIx::Class

use DBIx::Class::Helpers::Util 'get_namespace_parts';
use Lingua::EN::Inflect ();
use String::CamelCase ();
use DBIx::Class::Candy::Exports;

export_methods [qw(
   join_table
   generate_primary_key
   generate_has_manys
   generate_many_to_manys
   generate_relationships
   set_table
   add_join_columns
)];

sub _pluralize {
   my $self = shift;
   my $original = shift or return;
   return join q{_}, split /\s+/,
      Lingua::EN::Inflect::PL(join q{ }, split /_/, $original);
}

sub _defaults {
   my ($self, $params) = @_;

   $params->{namespace}           ||= [ get_namespace_parts($self) ]->[0];
   $params->{left_method}         ||= String::CamelCase::decamelize($params->{left_class});
   $params->{right_method}        ||= String::CamelCase::decamelize($params->{right_class});
   $params->{self_method}         ||= String::CamelCase::decamelize($self);
   $params->{left_method_plural}  ||= $self->_pluralize($params->{left_method});
   $params->{right_method_plural} ||= $self->_pluralize($params->{right_method});
   $params->{self_method_plural}  ||= $self->_pluralize($params->{self_method});

   return $params;
}

sub join_table {
   my ($self, $params) = @_;

   $self->set_table($params);
   $self->add_join_columns($params);
   $self->generate_relationships($params);
   $self->generate_primary_key($params);
}

sub generate_primary_key {
   my ($self, $params) = @_;

   $self->_defaults($params);
   $self->set_primary_key("$params->{left_method}_id", "$params->{right_method}_id");
}

sub generate_has_manys {
   my ($self, $params) = @_;

   $params = $self->_defaults($params);
   "$params->{namespace}::$params->{left_class}"->has_many(
      $params->{self_method} =>
      $self,
      "$params->{left_method}_id"
   );

   "$params->{namespace}::$params->{right_class}"->has_many(
      $params->{self_method} =>
      $self,
      "$params->{right_method}_id"
   );
}

sub generate_many_to_manys {
   my ($self, $params) = @_;
   $params = $self->_defaults($params);

   "$params->{namespace}::$params->{left_class}"->many_to_many(
      $params->{right_method_plural} =>
      $params->{self_method},
      $params->{right_method}
   );

   "$params->{namespace}::$params->{right_class}"->many_to_many(
      $params->{left_method_plural} =>
      $params->{self_method},
      $params->{left_method}
   );
}

sub generate_relationships {
   my ($self, $params) = @_;

   $params = $self->_defaults($params);
   $self->belongs_to(
      $params->{left_method} =>
      "$params->{namespace}::$params->{left_class}",
      "$params->{left_method}_id"
   );
   $self->belongs_to(
      $params->{right_method} =>
      "$params->{namespace}::$params->{right_class}",
      "$params->{right_method}_id"
   );
}

sub set_table {
   my ($self, $params) = @_;

   $self->table("$params->{left_class}_$params->{right_class}");
}

sub _add_join_column {
   my ($self, $params) = @_;

   my $class = $params->{class};
   my $method = $params->{method};

   my $default = {
      data_type   => 'integer',
      is_nullable => 0,
      is_numeric  => 1,
   };

   $self->ensure_class_loaded($class);
   my @datas = qw{is_nullable extra data_type size is_numeric};

   my @class_column_info = (
      map {
         my $info = $class->column_info($_);
         my $result = {};
         my $defined = undef;
         for (@datas) {
            if (defined $info->{$_}) {
               $defined = 1;
               $result->{$_} = $info->{$_};
            }
         }
         $result = $default unless $defined;
         $result;
      } $class->primary_columns
   );

   if (@class_column_info == 1) {
      $self->add_columns(
         "${method}_id" => $class_column_info[0],
      );
   } else {
      my $i = 0;
      for (@class_column_info) {
         $i++;
         $self->add_columns(
            "${method}_${i}_id" => $_
         );
      }
   }
}

sub add_join_columns {
   my ($self, $params) = @_;

   $params = $self->_defaults($params);

   my $l_class = "$params->{namespace}::$params->{left_class}";
   my $r_class = "$params->{namespace}::$params->{right_class}";

   $self->_add_join_column({
      class => $l_class,
      method => $params->{left_method}
   });

   $self->_add_join_column({
      class => $r_class,
      method => $params->{right_method}
   });
}

1;


__END__
=pod

=head1 NAME

DBIx::Class::Helper::Row::JoinTable - Easily set up join tables with DBIx::Class

=head1 VERSION

version 2.013002

=head1 SYNOPSIS

 package MyApp::Schema::Result::Foo_Bar;

 __PACKAGE__->load_components(qw{Helper::Row::JoinTable Core});

 __PACKAGE__->join_table({
    left_class   => 'Foo',
    left_method  => 'foo',
    right_class  => 'Bar',
    right_method => 'bar',
 });

 # the above is the same as:

 __PACKAGE__->table('Foo_Bar');
 __PACKAGE__->add_columns(
    foo_id => {
       data_type         => 'integer',
       is_nullable       => 0,
       is_numeric        => 1,
    },
    bar_id => {
       data_type         => 'integer',
       is_nullable       => 0,
       is_numeric        => 1,
    },
 );

 $self->set_primary_key(qw{foo_id bar_id});

 __PACKAGE__->belongs_to( foo => 'MyApp::Schema::Result::Foo' 'foo_id');
 __PACKAGE__->belongs_to( bar => 'MyApp::Schema::Result::Bar' 'bar_id');

or with L<DBIx::Class::Candy>:

 package MyApp::Schema::Result::Foo_Bar;

 use DBIx::Class::Candy -components => ['Helper::Row::JoinTable'];

 join_table {
    left_class   => 'Foo',
    left_method  => 'foo',
    right_class  => 'Bar',
    right_method => 'bar',
 };

=head1 METHODS

All the methods take a configuration hashref that looks like the following:

 {
    left_class          => 'Foo',
    left_method         => 'foo',     # see NOTE
    left_method_plural  => 'foos',    # see NOTE, not required, used for
                                      # many_to_many rel name in right_class
                                      # which is not generated by default
    right_class         => 'Bar',
    right_method        => 'bar',     # see NOTE
    right_method_plural => 'bars',    # see NOTE, not required, used for
                                      # many_to_many rel name in left_class
                                      # which is not generated by default
    namespace           => 'MyApp',   # default is guessed via *::Foo
    self_method         => 'foobars', # not required, used for setting the name of the
                                      # join table's relationship in a has_many
                                      # which is not generated by default
 }

=head2 join_table

This is the method that you probably want.  It will set your table, add
columns, set the primary key, and set up the relationships.

=head2 add_join_columns

Adds two non-nullable integer fields named C<"${left_method}_id"> and
C<"${right_method}_id"> respectively.

=head2 generate_has_manys

Installs methods into C<left_class> and C<right_class> to get to the join table.
The methods will be named what's passed into the configuration hashref as
C<self_method>.

=head2 generate_many_to_manys

Installs many_to_many methods into C<left_class> and C<right_class>.  The
methods will be named what's passed into the configuration hashref as
C<left_method_plural> for the C<right_class> and C<right_method_plural> for the
C<left_class>.

=head2 generate_primary_key

Sets C<"${left_method}_id"> and C<"${right_method}_id"> to be the primary key.

=head2 generate_relationships

This adds relationships to C<"${namespace}::Schema::Result::$left_class"> and
C<"${namespace}::Schema::Result::$left_class"> respectively.

=head2 set_table

This method sets the table to "${left_class}_${right_class}".

=head1 CANDY EXPORTS

If used in conjunction with L<DBIx::Class::Candy> this component will export:

=over

=item join_table

=item generate_primary_key

=item generate_has_manys

=item generate_many_to_manys

=item generate_relationships

=item set_table

=item add_join_columns

=back

=head2 NOTE

This module uses L<String::CamelCase> to default the method names and uses
L<Lingua::EN::Inflect> for pluralization.

=head1 CHANGES BETWEEN RELEASES

=head2 Changes since 0.*

Originally this module would use

       data_type         => 'integer',
       is_nullable       => 0,
       is_numeric        => 1,

for all joining columns.  It now infers C<data_type>, C<is_nullable>,
C<is_numeric>, and C<extra> from the foreign tables.

=head1 AUTHOR

Arthur Axel "fREW" Schmidt <frioux+cpan@gmail.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2012 by Arthur Axel "fREW" Schmidt.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut