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