* must use $UNIVERSAL::require::ERROR, $@ is not safe. See RT #44444
[dbsrgits/DBIx-Class-Schema-Loader.git] / lib / DBIx / Class / Schema / Loader / Base.pm
CommitLineData
996be9ee 1package DBIx::Class::Schema::Loader::Base;
2
3use strict;
4use warnings;
5use base qw/Class::Accessor::Fast/;
6use Class::C3;
fa994d3c 7use Carp::Clan qw/^DBIx::Class/;
996be9ee 8use UNIVERSAL::require;
9use DBIx::Class::Schema::Loader::RelBuilder;
10use Data::Dump qw/ dump /;
11use POSIX qw//;
dd03ee1a 12use File::Spec qw//;
419a2eeb 13use Cwd qw//;
7cab3ab7 14use Digest::MD5 qw//;
996be9ee 15require DBIx::Class;
16
a6db40af 17our $VERSION = '0.04005';
32f784fc 18
996be9ee 19__PACKAGE__->mk_ro_accessors(qw/
20 schema
21 schema_class
22
23 exclude
24 constraint
25 additional_classes
26 additional_base_classes
27 left_base_classes
28 components
29 resultset_components
59cfa251 30 skip_relationships
996be9ee 31 moniker_map
32 inflect_singular
33 inflect_plural
34 debug
35 dump_directory
d65cda9e 36 dump_overwrite
28b4691d 37 really_erase_my_files
f44ecc2f 38 use_namespaces
39 result_namespace
40 resultset_namespace
41 default_resultset_class
9c9c2f2b 42 schema_base_class
43 result_base_class
996be9ee 44
996be9ee 45 db_schema
46 _tables
47 classes
48 monikers
49 /);
50
51=head1 NAME
52
53DBIx::Class::Schema::Loader::Base - Base DBIx::Class::Schema::Loader Implementation.
54
55=head1 SYNOPSIS
56
57See L<DBIx::Class::Schema::Loader>
58
59=head1 DESCRIPTION
60
61This is the base class for the storage-specific C<DBIx::Class::Schema::*>
62classes, and implements the common functionality between them.
63
64=head1 CONSTRUCTOR OPTIONS
65
66These constructor options are the base options for
67L<DBIx::Class::Schema::Loader/loader_opts>. Available constructor options are:
68
59cfa251 69=head2 skip_relationships
996be9ee 70
59cfa251 71Skip setting up relationships. The default is to attempt the loading
72of relationships.
996be9ee 73
74=head2 debug
75
76If set to true, each constructive L<DBIx::Class> statement the loader
77decides to execute will be C<warn>-ed before execution.
78
d65cda9e 79=head2 db_schema
80
81Set the name of the schema to load (schema in the sense that your database
82vendor means it). Does not currently support loading more than one schema
83name.
84
996be9ee 85=head2 constraint
86
87Only load tables matching regex. Best specified as a qr// regex.
88
89=head2 exclude
90
91Exclude tables matching regex. Best specified as a qr// regex.
92
93=head2 moniker_map
94
8f9d7ce5 95Overrides the default table name to moniker translation. Can be either
96a hashref of table keys and moniker values, or a coderef for a translator
996be9ee 97function taking a single scalar table name argument and returning
98a scalar moniker. If the hash entry does not exist, or the function
99returns a false value, the code falls back to default behavior
100for that table name.
101
102The default behavior is: C<join '', map ucfirst, split /[\W_]+/, lc $table>,
103which is to say: lowercase everything, split up the table name into chunks
104anywhere a non-alpha-numeric character occurs, change the case of first letter
105of each chunk to upper case, and put the chunks back together. Examples:
106
107 Table Name | Moniker Name
108 ---------------------------
109 luser | Luser
110 luser_group | LuserGroup
111 luser-opts | LuserOpts
112
113=head2 inflect_plural
114
115Just like L</moniker_map> above (can be hash/code-ref, falls back to default
116if hash key does not exist or coderef returns false), but acts as a map
117for pluralizing relationship names. The default behavior is to utilize
118L<Lingua::EN::Inflect::Number/to_PL>.
119
120=head2 inflect_singular
121
122As L</inflect_plural> above, but for singularizing relationship names.
123Default behavior is to utilize L<Lingua::EN::Inflect::Number/to_S>.
124
9c9c2f2b 125=head2 schema_base_class
126
127Base class for your schema classes. Defaults to 'DBIx::Class::Schema'.
128
129=head2 result_base_class
130
131Base class for your table classes (aka result classes). Defaults to 'DBIx::Class'.
132
996be9ee 133=head2 additional_base_classes
134
135List of additional base classes all of your table classes will use.
136
137=head2 left_base_classes
138
139List of additional base classes all of your table classes will use
140that need to be leftmost.
141
142=head2 additional_classes
143
144List of additional classes which all of your table classes will use.
145
146=head2 components
147
148List of additional components to be loaded into all of your table
149classes. A good example would be C<ResultSetManager>.
150
151=head2 resultset_components
152
8f9d7ce5 153List of additional ResultSet components to be loaded into your table
996be9ee 154classes. A good example would be C<AlwaysRS>. Component
155C<ResultSetManager> will be automatically added to the above
156C<components> list if this option is set.
157
f44ecc2f 158=head2 use_namespaces
159
160Generate result class names suitable for
161L<DBIx::Class::Schema/load_namespaces> and call that instead of
162L<DBIx::Class::Schema/load_classes>. When using this option you can also
163specify any of the options for C<load_namespaces> (i.e. C<result_namespace>,
164C<resultset_namespace>, C<default_resultset_class>), and they will be added
165to the call (and the generated result class names adjusted appropriately).
166
996be9ee 167=head2 dump_directory
168
169This option is designed to be a tool to help you transition from this
170loader to a manually-defined schema when you decide it's time to do so.
171
172The value of this option is a perl libdir pathname. Within
173that directory this module will create a baseline manual
174L<DBIx::Class::Schema> module set, based on what it creates at runtime
175in memory.
176
177The created schema class will have the same classname as the one on
178which you are setting this option (and the ResultSource classes will be
7cab3ab7 179based on this name as well).
996be9ee 180
8f9d7ce5 181Normally you wouldn't hard-code this setting in your schema class, as it
996be9ee 182is meant for one-time manual usage.
183
184See L<DBIx::Class::Schema::Loader/dump_to_dir> for examples of the
185recommended way to access this functionality.
186
d65cda9e 187=head2 dump_overwrite
188
28b4691d 189Deprecated. See L</really_erase_my_files> below, which does *not* mean
190the same thing as the old C<dump_overwrite> setting from previous releases.
191
192=head2 really_erase_my_files
193
7cab3ab7 194Default false. If true, Loader will unconditionally delete any existing
195files before creating the new ones from scratch when dumping a schema to disk.
196
197The default behavior is instead to only replace the top portion of the
198file, up to and including the final stanza which contains
199C<# DO NOT MODIFY THIS OR ANYTHING ABOVE!>
200leaving any customizations you placed after that as they were.
201
28b4691d 202When C<really_erase_my_files> is not set, if the output file already exists,
7cab3ab7 203but the aforementioned final stanza is not found, or the checksum
204contained there does not match the generated contents, Loader will
205croak and not touch the file.
d65cda9e 206
28b4691d 207You should really be using version control on your schema classes (and all
208of the rest of your code for that matter). Don't blame me if a bug in this
209code wipes something out when it shouldn't have, you've been warned.
210
996be9ee 211=head1 METHODS
212
213None of these methods are intended for direct invocation by regular
214users of L<DBIx::Class::Schema::Loader>. Anything you can find here
215can also be found via standard L<DBIx::Class::Schema> methods somehow.
216
217=cut
218
219# ensure that a peice of object data is a valid arrayref, creating
220# an empty one or encapsulating whatever's there.
221sub _ensure_arrayref {
222 my $self = shift;
223
224 foreach (@_) {
225 $self->{$_} ||= [];
226 $self->{$_} = [ $self->{$_} ]
227 unless ref $self->{$_} eq 'ARRAY';
228 }
229}
230
231=head2 new
232
233Constructor for L<DBIx::Class::Schema::Loader::Base>, used internally
234by L<DBIx::Class::Schema::Loader>.
235
236=cut
237
238sub new {
239 my ( $class, %args ) = @_;
240
241 my $self = { %args };
242
243 bless $self => $class;
244
996be9ee 245 $self->_ensure_arrayref(qw/additional_classes
246 additional_base_classes
247 left_base_classes
248 components
249 resultset_components
250 /);
251
252 push(@{$self->{components}}, 'ResultSetManager')
253 if @{$self->{resultset_components}};
254
255 $self->{monikers} = {};
256 $self->{classes} = {};
257
996be9ee 258 $self->{schema_class} ||= ( ref $self->{schema} || $self->{schema} );
259 $self->{schema} ||= $self->{schema_class};
260
28b4691d 261 croak "dump_overwrite is deprecated. Please read the"
262 . " DBIx::Class::Schema::Loader::Base documentation"
263 if $self->{dump_overwrite};
264
e8ad6491 265 $self->{relbuilder} = DBIx::Class::Schema::Loader::RelBuilder->new(
266 $self->schema_class, $self->inflect_plural, $self->inflect_singular
267 ) if !$self->{skip_relationships};
268
996be9ee 269 $self;
270}
271
419a2eeb 272sub _find_file_in_inc {
273 my ($self, $file) = @_;
274
275 foreach my $prefix (@INC) {
276 my $fullpath = $prefix . '/' . $file;
277 return $fullpath if -f $fullpath;
278 }
279
280 return;
281}
282
996be9ee 283sub _load_external {
f96ef30f 284 my ($self, $class) = @_;
285
286 my $class_path = $class;
287 $class_path =~ s{::}{/}g;
288 $class_path .= '.pm';
289
290 my $inc_path = $self->_find_file_in_inc($class_path);
291
292 return if !$inc_path;
293
294 my $real_dump_path = $self->dump_directory
295 ? Cwd::abs_path(
296 File::Spec->catfile($self->dump_directory, $class_path)
297 )
298 : '';
299 my $real_inc_path = Cwd::abs_path($inc_path);
300 return if $real_inc_path eq $real_dump_path;
301
fa1c4dc2 302 # must use $UNIVERSAL::require::ERROR, $@ is not safe. See RT #44444 --kane
303 $class->require or
304 croak "Failed to load external class definition"
305 . " for '$class': $UNIVERSAL::require::ERROR";
f96ef30f 306
307 # If we make it to here, we loaded an external definition
308 warn qq/# Loaded external class definition for '$class'\n/
309 if $self->debug;
310
311 # The rest is only relevant when dumping
312 return if !$self->dump_directory;
313
314 croak 'Failed to locate actual external module file for '
315 . "'$class'"
316 if !$real_inc_path;
317 open(my $fh, '<', $real_inc_path)
318 or croak "Failed to open '$real_inc_path' for reading: $!";
319 $self->_ext_stmt($class,
320 qq|# These lines were loaded from '$real_inc_path' found in \@INC.|
321 .q|# They are now part of the custom portion of this file|
322 .q|# for you to hand-edit. If you do not either delete|
323 .q|# this section or remove that file from @INC, this section|
324 .q|# will be repeated redundantly when you re-create this|
325 .q|# file again via Loader!|
326 );
327 while(<$fh>) {
328 chomp;
329 $self->_ext_stmt($class, $_);
996be9ee 330 }
f96ef30f 331 $self->_ext_stmt($class,
70b72fab 332 qq|# End of lines loaded from '$real_inc_path' |
f96ef30f 333 );
334 close($fh)
335 or croak "Failed to close $real_inc_path: $!";
996be9ee 336}
337
338=head2 load
339
340Does the actual schema-construction work.
341
342=cut
343
344sub load {
345 my $self = shift;
346
b97c2c1e 347 $self->_load_tables($self->_tables_list);
348}
349
350=head2 rescan
351
a60b5b8d 352Arguments: schema
353
b97c2c1e 354Rescan the database for newly added tables. Does
a60b5b8d 355not process drops or changes. Returns a list of
356the newly added table monikers.
357
358The schema argument should be the schema class
359or object to be affected. It should probably
360be derived from the original schema_class used
361during L</load>.
b97c2c1e 362
363=cut
364
365sub rescan {
a60b5b8d 366 my ($self, $schema) = @_;
367
368 $self->{schema} = $schema;
b97c2c1e 369
370 my @created;
371 my @current = $self->_tables_list;
372 foreach my $table ($self->_tables_list) {
373 if(!exists $self->{_tables}->{$table}) {
374 push(@created, $table);
375 }
376 }
377
c39e3507 378 my $loaded = $self->_load_tables(@created);
a60b5b8d 379
c39e3507 380 return map { $self->monikers->{$_} } @$loaded;
b97c2c1e 381}
382
383sub _load_tables {
384 my ($self, @tables) = @_;
385
f96ef30f 386 # First, use _tables_list with constraint and exclude
387 # to get a list of tables to operate on
388
389 my $constraint = $self->constraint;
390 my $exclude = $self->exclude;
f96ef30f 391
b97c2c1e 392 @tables = grep { /$constraint/ } @tables if $constraint;
393 @tables = grep { ! /$exclude/ } @tables if $exclude;
f96ef30f 394
b97c2c1e 395 # Save the new tables to the tables list
a60b5b8d 396 foreach (@tables) {
397 $self->{_tables}->{$_} = 1;
398 }
f96ef30f 399
400 # Set up classes/monikers
401 {
402 no warnings 'redefine';
403 local *Class::C3::reinitialize = sub { };
404 use warnings;
405
406 $self->_make_src_class($_) for @tables;
407 }
408
409 Class::C3::reinitialize;
410
411 $self->_setup_src_meta($_) for @tables;
412
e8ad6491 413 if(!$self->skip_relationships) {
414 $self->_load_relationships($_) for @tables;
415 }
416
f96ef30f 417 $self->_load_external($_)
75451704 418 for map { $self->classes->{$_} } @tables;
f96ef30f 419
996be9ee 420 $self->_dump_to_dir if $self->dump_directory;
421
5223f24a 422 # Drop temporary cache
423 delete $self->{_cache};
424
c39e3507 425 return \@tables;
996be9ee 426}
427
428sub _get_dump_filename {
429 my ($self, $class) = (@_);
430
431 $class =~ s{::}{/}g;
432 return $self->dump_directory . q{/} . $class . q{.pm};
433}
434
435sub _ensure_dump_subdirs {
436 my ($self, $class) = (@_);
437
438 my @name_parts = split(/::/, $class);
dd03ee1a 439 pop @name_parts; # we don't care about the very last element,
440 # which is a filename
441
996be9ee 442 my $dir = $self->dump_directory;
7cab3ab7 443 while (1) {
444 if(!-d $dir) {
25328cc4 445 mkdir($dir) or croak "mkdir('$dir') failed: $!";
996be9ee 446 }
7cab3ab7 447 last if !@name_parts;
448 $dir = File::Spec->catdir($dir, shift @name_parts);
996be9ee 449 }
450}
451
452sub _dump_to_dir {
453 my ($self) = @_;
454
455 my $target_dir = $self->dump_directory;
d65cda9e 456
fc2b71fd 457 my $schema_class = $self->schema_class;
9c9c2f2b 458 my $schema_base_class = $self->schema_base_class || 'DBIx::Class::Schema';
996be9ee 459
25328cc4 460 croak "Must specify target directory for dumping!" if ! $target_dir;
996be9ee 461
fc2b71fd 462 warn "Dumping manual schema for $schema_class to directory $target_dir ...\n";
996be9ee 463
7cab3ab7 464 my $schema_text =
465 qq|package $schema_class;\n\n|
466 . qq|use strict;\nuse warnings;\n\n|
9c9c2f2b 467 . qq|use base '$schema_base_class';\n\n|;
f44ecc2f 468
469
470 if ($self->use_namespaces) {
471 $schema_text .= qq|__PACKAGE__->load_namespaces|;
472 my $namespace_options;
473 for my $attr (qw(result_namespace
474 resultset_namespace
475 default_resultset_class)) {
476 if ($self->$attr) {
477 $namespace_options .= qq| $attr => '| . $self->$attr . qq|',\n|
478 }
479 }
480 $schema_text .= qq|(\n$namespace_options)| if $namespace_options;
481 $schema_text .= qq|;\n|;
482 }
483 else {
484 $schema_text .= qq|__PACKAGE__->load_classes;\n|;
485
486 }
996be9ee 487
7cab3ab7 488 $self->_write_classfile($schema_class, $schema_text);
996be9ee 489
9c9c2f2b 490 my $result_base_class = $self->result_base_class || 'DBIx::Class';
491
7cab3ab7 492 foreach my $src_class (sort keys %{$self->{_dump_storage}}) {
493 my $src_text =
494 qq|package $src_class;\n\n|
495 . qq|use strict;\nuse warnings;\n\n|
9c9c2f2b 496 . qq|use base '$result_base_class';\n\n|;
996be9ee 497
7cab3ab7 498 $self->_write_classfile($src_class, $src_text);
02356864 499 }
996be9ee 500
7cab3ab7 501 warn "Schema dump completed.\n";
502}
503
504sub _write_classfile {
505 my ($self, $class, $text) = @_;
506
507 my $filename = $self->_get_dump_filename($class);
508 $self->_ensure_dump_subdirs($class);
509
28b4691d 510 if (-f $filename && $self->really_erase_my_files) {
7cab3ab7 511 warn "Deleting existing file '$filename' due to "
28b4691d 512 . "'really_erase_my_files' setting\n";
7cab3ab7 513 unlink($filename);
514 }
515
419a2eeb 516 my $custom_content = $self->_get_custom_content($class, $filename);
7cab3ab7 517
a4476f41 518 $custom_content ||= qq|\n\n# You can replace this text with custom|
7cab3ab7 519 . qq| content, and it will be preserved on regeneration|
520 . qq|\n1;\n|;
521
522 $text .= qq|$_\n|
523 for @{$self->{_dump_storage}->{$class} || []};
524
525 $text .= qq|\n\n# Created by DBIx::Class::Schema::Loader|
526 . qq| v| . $DBIx::Class::Schema::Loader::VERSION
527 . q| @ | . POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime)
528 . qq|\n# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:|;
529
530 open(my $fh, '>', $filename)
531 or croak "Cannot open '$filename' for writing: $!";
532
533 # Write the top half and its MD5 sum
a4476f41 534 print $fh $text . Digest::MD5::md5_base64($text) . "\n";
7cab3ab7 535
536 # Write out anything loaded via external partial class file in @INC
537 print $fh qq|$_\n|
538 for @{$self->{_ext_storage}->{$class} || []};
539
540 print $fh $custom_content;
541
542 close($fh)
543 or croak "Cannot close '$filename': $!";
544}
545
546sub _get_custom_content {
547 my ($self, $class, $filename) = @_;
548
549 return if ! -f $filename;
550 open(my $fh, '<', $filename)
551 or croak "Cannot open '$filename' for reading: $!";
552
553 my $mark_re =
419a2eeb 554 qr{^(# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:)([A-Za-z0-9/+]{22})\n};
7cab3ab7 555
556 my $found = 0;
557 my $buffer = '';
558 while(<$fh>) {
559 if(!$found && /$mark_re/) {
560 $found = 1;
561 $buffer .= $1;
7cab3ab7 562 croak "Checksum mismatch in '$filename'"
419a2eeb 563 if Digest::MD5::md5_base64($buffer) ne $2;
7cab3ab7 564
565 $buffer = '';
566 }
567 else {
568 $buffer .= $_;
569 }
996be9ee 570 }
571
28b4691d 572 croak "Cannot not overwrite '$filename' without 'really_erase_my_files',"
419a2eeb 573 . " it does not appear to have been generated by Loader"
5ef3c771 574 if !$found;
575
7cab3ab7 576 return $buffer;
996be9ee 577}
578
579sub _use {
580 my $self = shift;
581 my $target = shift;
cb54990b 582 my $evalstr;
996be9ee 583
584 foreach (@_) {
cb54990b 585 warn "$target: use $_;" if $self->debug;
996be9ee 586 $self->_raw_stmt($target, "use $_;");
fa1c4dc2 587 $_->require or croak ($_ . "->require: $UNIVERSAL::require::ERROR");
cb54990b 588 $evalstr .= "package $target; use $_;";
996be9ee 589 }
cb54990b 590 eval $evalstr if $evalstr;
591 croak $@ if $@;
996be9ee 592}
593
594sub _inject {
595 my $self = shift;
596 my $target = shift;
597 my $schema_class = $self->schema_class;
598
599 my $blist = join(q{ }, @_);
cb54990b 600 warn "$target: use base qw/ $blist /;" if $self->debug && @_;
996be9ee 601 $self->_raw_stmt($target, "use base qw/ $blist /;") if @_;
996be9ee 602 foreach (@_) {
fa1c4dc2 603 $_->require or croak ($_ . "->require: $UNIVERSAL::require::ERROR");
996be9ee 604 $schema_class->inject_base($target, $_);
605 }
606}
607
f96ef30f 608# Create class with applicable bases, setup monikers, etc
609sub _make_src_class {
610 my ($self, $table) = @_;
996be9ee 611
a13b2803 612 my $schema = $self->schema;
613 my $schema_class = $self->schema_class;
996be9ee 614
f96ef30f 615 my $table_moniker = $self->_table2moniker($table);
f44ecc2f 616 my @result_namespace = ($schema_class);
617 if ($self->use_namespaces) {
618 my $result_namespace = $self->result_namespace || 'Result';
619 if ($result_namespace =~ /^\+(.*)/) {
620 # Fully qualified namespace
621 @result_namespace = ($1)
622 }
623 else {
624 # Relative namespace
625 push @result_namespace, $result_namespace;
626 }
627 }
628 my $table_class = join(q{::}, @result_namespace, $table_moniker);
996be9ee 629
f96ef30f 630 my $table_normalized = lc $table;
631 $self->classes->{$table} = $table_class;
632 $self->classes->{$table_normalized} = $table_class;
633 $self->monikers->{$table} = $table_moniker;
634 $self->monikers->{$table_normalized} = $table_moniker;
996be9ee 635
f96ef30f 636 { no strict 'refs'; @{"${table_class}::ISA"} = qw/DBIx::Class/ }
996be9ee 637
f96ef30f 638 $self->_use ($table_class, @{$self->additional_classes});
639 $self->_inject($table_class, @{$self->additional_base_classes});
996be9ee 640
605fcea8 641 $self->_dbic_stmt($table_class, 'load_components', @{$self->components}, 'Core');
996be9ee 642
f96ef30f 643 $self->_dbic_stmt($table_class, 'load_resultset_components', @{$self->resultset_components})
644 if @{$self->resultset_components};
645 $self->_inject($table_class, @{$self->left_base_classes});
646}
996be9ee 647
f96ef30f 648# Set up metadata (cols, pks, etc) and register the class with the schema
649sub _setup_src_meta {
650 my ($self, $table) = @_;
996be9ee 651
f96ef30f 652 my $schema = $self->schema;
653 my $schema_class = $self->schema_class;
a13b2803 654
f96ef30f 655 my $table_class = $self->classes->{$table};
656 my $table_moniker = $self->monikers->{$table};
996be9ee 657
f96ef30f 658 $self->_dbic_stmt($table_class,'table',$table);
996be9ee 659
f96ef30f 660 my $cols = $self->_table_columns($table);
661 my $col_info;
662 eval { $col_info = $self->_columns_info_for($table) };
663 if($@) {
664 $self->_dbic_stmt($table_class,'add_columns',@$cols);
665 }
666 else {
667 my %col_info_lc = map { lc($_), $col_info->{$_} } keys %$col_info;
668 $self->_dbic_stmt(
669 $table_class,
670 'add_columns',
671 map { $_, ($col_info_lc{$_}||{}) } @$cols
672 );
996be9ee 673 }
674
f96ef30f 675 my $pks = $self->_table_pk_info($table) || [];
676 @$pks ? $self->_dbic_stmt($table_class,'set_primary_key',@$pks)
677 : carp("$table has no primary key");
996be9ee 678
f96ef30f 679 my $uniqs = $self->_table_uniq_info($table) || [];
6ac18b87 680 $self->_dbic_stmt($table_class,'add_unique_constraint',@$_) for (@$uniqs);
996be9ee 681
f96ef30f 682 $schema_class->register_class($table_moniker, $table_class);
683 $schema->register_class($table_moniker, $table_class) if $schema ne $schema_class;
996be9ee 684}
685
686=head2 tables
687
688Returns a sorted list of loaded tables, using the original database table
689names.
690
691=cut
692
693sub tables {
694 my $self = shift;
695
b97c2c1e 696 return keys %{$self->_tables};
996be9ee 697}
698
699# Make a moniker from a table
700sub _table2moniker {
701 my ( $self, $table ) = @_;
702
703 my $moniker;
704
705 if( ref $self->moniker_map eq 'HASH' ) {
706 $moniker = $self->moniker_map->{$table};
707 }
708 elsif( ref $self->moniker_map eq 'CODE' ) {
709 $moniker = $self->moniker_map->($table);
710 }
711
712 $moniker ||= join '', map ucfirst, split /[\W_]+/, lc $table;
713
714 return $moniker;
715}
716
717sub _load_relationships {
e8ad6491 718 my ($self, $table) = @_;
996be9ee 719
e8ad6491 720 my $tbl_fk_info = $self->_table_fk_info($table);
721 foreach my $fkdef (@$tbl_fk_info) {
722 $fkdef->{remote_source} =
723 $self->monikers->{delete $fkdef->{remote_table}};
996be9ee 724 }
725
e8ad6491 726 my $local_moniker = $self->monikers->{$table};
727 my $rel_stmts = $self->{relbuilder}->generate_code($local_moniker, $tbl_fk_info);
996be9ee 728
996be9ee 729 foreach my $src_class (sort keys %$rel_stmts) {
730 my $src_stmts = $rel_stmts->{$src_class};
731 foreach my $stmt (@$src_stmts) {
732 $self->_dbic_stmt($src_class,$stmt->{method},@{$stmt->{args}});
733 }
734 }
735}
736
737# Overload these in driver class:
738
739# Returns an arrayref of column names
740sub _table_columns { croak "ABSTRACT METHOD" }
741
742# Returns arrayref of pk col names
743sub _table_pk_info { croak "ABSTRACT METHOD" }
744
745# Returns an arrayref of uniqs [ [ foo => [ col1, col2 ] ], [ bar => [ ... ] ] ]
746sub _table_uniq_info { croak "ABSTRACT METHOD" }
747
748# Returns an arrayref of foreign key constraints, each
749# being a hashref with 3 keys:
750# local_columns (arrayref), remote_columns (arrayref), remote_table
751sub _table_fk_info { croak "ABSTRACT METHOD" }
752
753# Returns an array of lower case table names
754sub _tables_list { croak "ABSTRACT METHOD" }
755
756# Execute a constructive DBIC class method, with debug/dump_to_dir hooks.
757sub _dbic_stmt {
758 my $self = shift;
759 my $class = shift;
760 my $method = shift;
761
762 if(!$self->debug && !$self->dump_directory) {
763 $class->$method(@_);
764 return;
765 }
766
767 my $args = dump(@_);
768 $args = '(' . $args . ')' if @_ < 2;
769 my $stmt = $method . $args . q{;};
770
771 warn qq|$class\->$stmt\n| if $self->debug;
772 $class->$method(@_);
773 $self->_raw_stmt($class, '__PACKAGE__->' . $stmt);
774}
775
776# Store a raw source line for a class (for dumping purposes)
777sub _raw_stmt {
778 my ($self, $class, $stmt) = @_;
779 push(@{$self->{_dump_storage}->{$class}}, $stmt) if $self->dump_directory;
780}
781
7cab3ab7 782# Like above, but separately for the externally loaded stuff
783sub _ext_stmt {
784 my ($self, $class, $stmt) = @_;
785 push(@{$self->{_ext_storage}->{$class}}, $stmt) if $self->dump_directory;
786}
787
996be9ee 788=head2 monikers
789
8f9d7ce5 790Returns a hashref of loaded table to moniker mappings. There will
996be9ee 791be two entries for each table, the original name and the "normalized"
792name, in the case that the two are different (such as databases
793that like uppercase table names, or preserve your original mixed-case
794definitions, or what-have-you).
795
796=head2 classes
797
8f9d7ce5 798Returns a hashref of table to class mappings. In some cases it will
996be9ee 799contain multiple entries per table for the original and normalized table
800names, as above in L</monikers>.
801
802=head1 SEE ALSO
803
804L<DBIx::Class::Schema::Loader>
805
806=cut
807
8081;