for clarity, extracted POD generation into its own method
[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;
65e705c3 5use base qw/Class::Accessor::Grouped Class::C3::Componentised/;
996be9ee 6use Class::C3;
fa994d3c 7use Carp::Clan qw/^DBIx::Class/;
996be9ee 8use DBIx::Class::Schema::Loader::RelBuilder;
9use Data::Dump qw/ dump /;
10use POSIX qw//;
dd03ee1a 11use File::Spec qw//;
419a2eeb 12use Cwd qw//;
7cab3ab7 13use Digest::MD5 qw//;
22270947 14use Lingua::EN::Inflect::Number qw//;
af31090c 15use File::Temp qw//;
16use Class::Unload;
996be9ee 17require DBIx::Class;
18
0a701ff3 19our $VERSION = '0.04999_12';
32f784fc 20
3d95f9ff 21__PACKAGE__->mk_group_ro_accessors('simple', qw/
996be9ee 22 schema
23 schema_class
24
25 exclude
26 constraint
27 additional_classes
28 additional_base_classes
29 left_base_classes
30 components
31 resultset_components
59cfa251 32 skip_relationships
0ca61324 33 skip_load_external
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
9c9c2f2b 45 schema_base_class
46 result_base_class
639a1367 47 overwrite_modifications
996be9ee 48
c8c27020 49 relationship_attrs
50
996be9ee 51 db_schema
52 _tables
53 classes
f53dcdf0 54 _upgrading_classes
996be9ee 55 monikers
106a976a 56 dynamic
a8d229ff 57 naming
65e705c3 58/);
59
996be9ee 60
3d95f9ff 61__PACKAGE__->mk_group_accessors('simple', qw/
01012543 62 version_to_dump
1c95b304 63 schema_version_to_dump
f53dcdf0 64 _upgrading_from
01012543 65/);
66
996be9ee 67=head1 NAME
68
69DBIx::Class::Schema::Loader::Base - Base DBIx::Class::Schema::Loader Implementation.
70
71=head1 SYNOPSIS
72
73See L<DBIx::Class::Schema::Loader>
74
75=head1 DESCRIPTION
76
77This is the base class for the storage-specific C<DBIx::Class::Schema::*>
78classes, and implements the common functionality between them.
79
80=head1 CONSTRUCTOR OPTIONS
81
82These constructor options are the base options for
29ddb54c 83L<DBIx::Class::Schema::Loader/loader_options>. Available constructor options are:
3953cbee 84
59cfa251 85=head2 skip_relationships
996be9ee 86
59cfa251 87Skip setting up relationships. The default is to attempt the loading
88of relationships.
996be9ee 89
0ca61324 90=head2 skip_load_external
91
92Skip loading of other classes in @INC. The default is to merge all other classes
93with the same name found in @INC into the schema file we are creating.
94
9a95164d 95=head2 naming
96
97Static schemas (ones dumped to disk) will, by default, use the new-style 0.05XXX
98relationship names and singularized Results, unless you're overwriting an
99existing dump made by a 0.04XXX version of L<DBIx::Class::Schema::Loader>, in
100which case the backward compatible RelBuilder will be activated, and
101singularization will be turned off.
102
103Specifying
104
105 naming => 'v5'
106
107will disable the backward-compatible RelBuilder and use
108the new-style relationship names along with singularized Results, even when
109overwriting a dump made with an earlier version.
110
111The option also takes a hashref:
112
a8d229ff 113 naming => { relationships => 'v5', monikers => 'v4' }
114
115The keys are:
116
117=over 4
118
119=item relationships
120
121How to name relationship accessors.
122
123=item monikers
124
125How to name Result classes.
126
127=back
9a95164d 128
129The values can be:
130
131=over 4
132
133=item current
134
135Latest default style, whatever that happens to be.
136
137=item v5
138
139Version 0.05XXX style.
140
141=item v4
142
143Version 0.04XXX style.
144
145=back
146
147Dynamic schemas will always default to the 0.04XXX relationship names and won't
148singularize Results for backward compatibility, to activate the new RelBuilder
149and singularization put this in your C<Schema.pm> file:
150
151 __PACKAGE__->naming('current');
152
153Or if you prefer to use 0.05XXX features but insure that nothing breaks in the
154next major version upgrade:
155
156 __PACKAGE__->naming('v5');
157
c8c27020 158=head2 relationship_attrs
159
160Hashref of attributes to pass to each generated relationship, listed
161by type. Also supports relationship type 'all', containing options to
162pass to all generated relationships. Attributes set for more specific
163relationship types override those set in 'all'.
164
165For example:
166
167 relationship_attrs => {
168 all => { cascade_delete => 0 },
169 has_many => { cascade_delete => 1 },
170 },
171
172will set the C<cascade_delete> option to 0 for all generated relationships,
173except for C<has_many>, which will have cascade_delete as 1.
174
175NOTE: this option is not supported if v4 backward-compatible naming is
176set either globally (naming => 'v4') or just for relationships.
177
996be9ee 178=head2 debug
179
180If set to true, each constructive L<DBIx::Class> statement the loader
181decides to execute will be C<warn>-ed before execution.
182
d65cda9e 183=head2 db_schema
184
185Set the name of the schema to load (schema in the sense that your database
186vendor means it). Does not currently support loading more than one schema
187name.
188
996be9ee 189=head2 constraint
190
191Only load tables matching regex. Best specified as a qr// regex.
192
193=head2 exclude
194
195Exclude tables matching regex. Best specified as a qr// regex.
196
197=head2 moniker_map
198
8f9d7ce5 199Overrides the default table name to moniker translation. Can be either
200a hashref of table keys and moniker values, or a coderef for a translator
996be9ee 201function taking a single scalar table name argument and returning
202a scalar moniker. If the hash entry does not exist, or the function
203returns a false value, the code falls back to default behavior
204for that table name.
205
9cc8e7e1 206The default behavior is to singularize the table name, and: C<join '', map
207ucfirst, split /[\W_]+/, lc $table>, which is to say: lowercase everything,
208split up the table name into chunks anywhere a non-alpha-numeric character
209occurs, change the case of first letter of each chunk to upper case, and put
210the chunks back together. Examples:
996be9ee 211
212 Table Name | Moniker Name
213 ---------------------------
214 luser | Luser
215 luser_group | LuserGroup
216 luser-opts | LuserOpts
217
218=head2 inflect_plural
219
220Just like L</moniker_map> above (can be hash/code-ref, falls back to default
221if hash key does not exist or coderef returns false), but acts as a map
222for pluralizing relationship names. The default behavior is to utilize
223L<Lingua::EN::Inflect::Number/to_PL>.
224
225=head2 inflect_singular
226
227As L</inflect_plural> above, but for singularizing relationship names.
228Default behavior is to utilize L<Lingua::EN::Inflect::Number/to_S>.
229
9c9c2f2b 230=head2 schema_base_class
231
232Base class for your schema classes. Defaults to 'DBIx::Class::Schema'.
233
234=head2 result_base_class
235
2229729e 236Base class for your table classes (aka result classes). Defaults to
237'DBIx::Class::Core'.
9c9c2f2b 238
996be9ee 239=head2 additional_base_classes
240
241List of additional base classes all of your table classes will use.
242
243=head2 left_base_classes
244
245List of additional base classes all of your table classes will use
246that need to be leftmost.
247
248=head2 additional_classes
249
250List of additional classes which all of your table classes will use.
251
252=head2 components
253
254List of additional components to be loaded into all of your table
255classes. A good example would be C<ResultSetManager>.
256
257=head2 resultset_components
258
8f9d7ce5 259List of additional ResultSet components to be loaded into your table
996be9ee 260classes. A good example would be C<AlwaysRS>. Component
261C<ResultSetManager> will be automatically added to the above
262C<components> list if this option is set.
263
f44ecc2f 264=head2 use_namespaces
265
266Generate result class names suitable for
267L<DBIx::Class::Schema/load_namespaces> and call that instead of
268L<DBIx::Class::Schema/load_classes>. When using this option you can also
269specify any of the options for C<load_namespaces> (i.e. C<result_namespace>,
270C<resultset_namespace>, C<default_resultset_class>), and they will be added
271to the call (and the generated result class names adjusted appropriately).
272
996be9ee 273=head2 dump_directory
274
275This option is designed to be a tool to help you transition from this
276loader to a manually-defined schema when you decide it's time to do so.
277
278The value of this option is a perl libdir pathname. Within
279that directory this module will create a baseline manual
280L<DBIx::Class::Schema> module set, based on what it creates at runtime
281in memory.
282
283The created schema class will have the same classname as the one on
284which you are setting this option (and the ResultSource classes will be
7cab3ab7 285based on this name as well).
996be9ee 286
8f9d7ce5 287Normally you wouldn't hard-code this setting in your schema class, as it
996be9ee 288is meant for one-time manual usage.
289
290See L<DBIx::Class::Schema::Loader/dump_to_dir> for examples of the
291recommended way to access this functionality.
292
d65cda9e 293=head2 dump_overwrite
294
28b4691d 295Deprecated. See L</really_erase_my_files> below, which does *not* mean
296the same thing as the old C<dump_overwrite> setting from previous releases.
297
298=head2 really_erase_my_files
299
7cab3ab7 300Default false. If true, Loader will unconditionally delete any existing
301files before creating the new ones from scratch when dumping a schema to disk.
302
303The default behavior is instead to only replace the top portion of the
304file, up to and including the final stanza which contains
305C<# DO NOT MODIFY THIS OR ANYTHING ABOVE!>
306leaving any customizations you placed after that as they were.
307
28b4691d 308When C<really_erase_my_files> is not set, if the output file already exists,
7cab3ab7 309but the aforementioned final stanza is not found, or the checksum
310contained there does not match the generated contents, Loader will
311croak and not touch the file.
d65cda9e 312
28b4691d 313You should really be using version control on your schema classes (and all
314of the rest of your code for that matter). Don't blame me if a bug in this
315code wipes something out when it shouldn't have, you've been warned.
316
639a1367 317=head2 overwrite_modifications
318
319Default false. If false, when updating existing files, Loader will
320refuse to modify any Loader-generated code that has been modified
321since its last run (as determined by the checksum Loader put in its
322comment lines).
323
324If true, Loader will discard any manual modifications that have been
325made to Loader-generated code.
326
327Again, you should be using version control on your schema classes. Be
328careful with this option.
329
996be9ee 330=head1 METHODS
331
332None of these methods are intended for direct invocation by regular
333users of L<DBIx::Class::Schema::Loader>. Anything you can find here
334can also be found via standard L<DBIx::Class::Schema> methods somehow.
335
336=cut
337
66afce69 338use constant CURRENT_V => 'v5';
339
996be9ee 340# ensure that a peice of object data is a valid arrayref, creating
341# an empty one or encapsulating whatever's there.
342sub _ensure_arrayref {
343 my $self = shift;
344
345 foreach (@_) {
346 $self->{$_} ||= [];
347 $self->{$_} = [ $self->{$_} ]
348 unless ref $self->{$_} eq 'ARRAY';
349 }
350}
351
352=head2 new
353
354Constructor for L<DBIx::Class::Schema::Loader::Base>, used internally
355by L<DBIx::Class::Schema::Loader>.
356
357=cut
358
359sub new {
360 my ( $class, %args ) = @_;
361
362 my $self = { %args };
363
364 bless $self => $class;
365
996be9ee 366 $self->_ensure_arrayref(qw/additional_classes
367 additional_base_classes
368 left_base_classes
369 components
370 resultset_components
371 /);
372
373 push(@{$self->{components}}, 'ResultSetManager')
374 if @{$self->{resultset_components}};
375
376 $self->{monikers} = {};
377 $self->{classes} = {};
f53dcdf0 378 $self->{_upgrading_classes} = {};
996be9ee 379
996be9ee 380 $self->{schema_class} ||= ( ref $self->{schema} || $self->{schema} );
381 $self->{schema} ||= $self->{schema_class};
382
28b4691d 383 croak "dump_overwrite is deprecated. Please read the"
384 . " DBIx::Class::Schema::Loader::Base documentation"
385 if $self->{dump_overwrite};
386
af31090c 387 $self->{dynamic} = ! $self->{dump_directory};
79193756 388 $self->{temp_directory} ||= File::Temp::tempdir( 'dbicXXXX',
af31090c 389 TMPDIR => 1,
390 CLEANUP => 1,
391 );
392
79193756 393 $self->{dump_directory} ||= $self->{temp_directory};
394
01012543 395 $self->version_to_dump($DBIx::Class::Schema::Loader::VERSION);
1c95b304 396 $self->schema_version_to_dump($DBIx::Class::Schema::Loader::VERSION);
01012543 397
66afce69 398 if ((not ref $self->naming) && defined $self->naming) {
9cc8e7e1 399 my $naming_ver = $self->naming;
a8d229ff 400 $self->{naming} = {
401 relationships => $naming_ver,
402 monikers => $naming_ver,
403 };
404 }
405
66afce69 406 if ($self->naming) {
407 for (values %{ $self->naming }) {
408 $_ = CURRENT_V if $_ eq 'current';
409 }
410 }
411 $self->{naming} ||= {};
412
7824616e 413 $self->_check_back_compat;
9c465d2c 414
7824616e 415 $self;
416}
af31090c 417
7824616e 418sub _check_back_compat {
419 my ($self) = @_;
e8ad6491 420
a8d229ff 421# dynamic schemas will always be in 0.04006 mode, unless overridden
106a976a 422 if ($self->dynamic) {
fb3bb595 423# just in case, though no one is likely to dump a dynamic schema
1c95b304 424 $self->schema_version_to_dump('0.04006');
a8d229ff 425
66afce69 426 if (not %{ $self->naming }) {
427 warn <<EOF unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
428
429Dynamic schema detected, will run in 0.04006 mode.
430
431Set the 'naming' attribute or the SCHEMA_LOADER_BACKCOMPAT environment variable
432to disable this warning.
a0e0a56a 433
434See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 for more
435details.
66afce69 436EOF
437 }
f53dcdf0 438 else {
439 $self->_upgrading_from('v4');
440 }
66afce69 441
a8d229ff 442 $self->naming->{relationships} ||= 'v4';
443 $self->naming->{monikers} ||= 'v4';
444
01012543 445 return;
446 }
447
448# otherwise check if we need backcompat mode for a static schema
7824616e 449 my $filename = $self->_get_dump_filename($self->schema_class);
450 return unless -e $filename;
451
452 open(my $fh, '<', $filename)
453 or croak "Cannot open '$filename' for reading: $!";
454
455 while (<$fh>) {
01012543 456 if (/^# Created by DBIx::Class::Schema::Loader v((\d+)\.(\d+))/) {
457 my $real_ver = $1;
a8d229ff 458
a8d229ff 459 # XXX when we go past .0 this will need fixing
460 my ($v) = $real_ver =~ /([1-9])/;
461 $v = "v$v";
462
8b7749d6 463 last if $v eq CURRENT_V || $real_ver =~ /^0\.04999/;
a0e0a56a 464
465 if (not %{ $self->naming }) {
466 warn <<"EOF" unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
467
468Version $real_ver static schema detected, turning on backcompat mode.
469
470Set the 'naming' attribute or the SCHEMA_LOADER_BACKCOMPAT environment variable
471to disable this warning.
472
473See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 for more
474details.
475EOF
476 }
f53dcdf0 477 else {
478 $self->_upgrading_from($v);
479 }
a0e0a56a 480
a8d229ff 481 $self->naming->{relationships} ||= $v;
482 $self->naming->{monikers} ||= $v;
483
a0e0a56a 484 $self->schema_version_to_dump($real_ver);
485
7824616e 486 last;
487 }
488 }
489 close $fh;
996be9ee 490}
491
419a2eeb 492sub _find_file_in_inc {
493 my ($self, $file) = @_;
494
495 foreach my $prefix (@INC) {
af31090c 496 my $fullpath = File::Spec->catfile($prefix, $file);
497 return $fullpath if -f $fullpath
498 and Cwd::abs_path($fullpath) ne
00fb1678 499 (Cwd::abs_path(File::Spec->catfile($self->dump_directory, $file)) || '');
419a2eeb 500 }
501
502 return;
503}
504
fb3bb595 505sub _class_path {
f96ef30f 506 my ($self, $class) = @_;
507
508 my $class_path = $class;
509 $class_path =~ s{::}{/}g;
510 $class_path .= '.pm';
511
fb3bb595 512 return $class_path;
513}
514
515sub _find_class_in_inc {
516 my ($self, $class) = @_;
517
518 return $self->_find_file_in_inc($self->_class_path($class));
519}
520
521sub _load_external {
522 my ($self, $class) = @_;
523
0ca61324 524 return if $self->{skip_load_external};
525
ffc705f3 526 # so that we don't load our own classes, under any circumstances
527 local *INC = [ grep $_ ne $self->dump_directory, @INC ];
528
fb3bb595 529 my $real_inc_path = $self->_find_class_in_inc($class);
f96ef30f 530
ffc705f3 531 my $old_class = $self->_upgrading_classes->{$class}
532 if $self->_upgrading_from;
533
534 my $old_real_inc_path = $self->_find_class_in_inc($old_class)
535 if $old_class && $old_class ne $class;
536
537 return unless $real_inc_path || $old_real_inc_path;
538
539 if ($real_inc_path) {
540 # If we make it to here, we loaded an external definition
541 warn qq/# Loaded external class definition for '$class'\n/
542 if $self->debug;
543
544 open(my $fh, '<', $real_inc_path)
545 or croak "Failed to open '$real_inc_path' for reading: $!";
546 $self->_ext_stmt($class,
547 qq|# These lines were loaded from '$real_inc_path' found in \@INC.\n|
548 .qq|# They are now part of the custom portion of this file\n|
549 .qq|# for you to hand-edit. If you do not either delete\n|
550 .qq|# this section or remove that file from \@INC, this section\n|
551 .qq|# will be repeated redundantly when you re-create this\n|
552 .qq|# file again via Loader!\n|
553 );
554 while(<$fh>) {
555 chomp;
556 $self->_ext_stmt($class, $_);
557 }
558 $self->_ext_stmt($class,
559 qq|# End of lines loaded from '$real_inc_path' |
560 );
561 close($fh)
562 or croak "Failed to close $real_inc_path: $!";
563
564 if ($self->dynamic) { # load the class too
565 # kill redefined warnings
502b65d4 566 my $warn_handler = $SIG{__WARN__} || sub { warn @_ };
ffc705f3 567 local $SIG{__WARN__} = sub {
502b65d4 568 $warn_handler->(@_)
569 unless $_[0] =~ /^Subroutine \S+ redefined/;
ffc705f3 570 };
571 do $real_inc_path;
572 die $@ if $@;
573 }
996be9ee 574 }
106a976a 575
ffc705f3 576 if ($old_real_inc_path) {
577 open(my $fh, '<', $old_real_inc_path)
578 or croak "Failed to open '$old_real_inc_path' for reading: $!";
579 $self->_ext_stmt($class, <<"EOF");
580
581# These lines were loaded from '$old_real_inc_path', based on the Result class
582# name that would have been created by an 0.04006 version of the Loader. For a
583# static schema, this happens only once during upgrade.
584EOF
585 if ($self->dynamic) {
586 warn <<"EOF";
587
588Detected external content in '$old_real_inc_path', a class name that would have
589been used by an 0.04006 version of the Loader.
590
591* PLEASE RENAME THIS CLASS: from '$old_class' to '$class', as that is the
592new name of the Result.
593EOF
594 # kill redefined warnings
502b65d4 595 my $warn_handler = $SIG{__WARN__} || sub { warn @_ };
ffc705f3 596 local $SIG{__WARN__} = sub {
502b65d4 597 $warn_handler->(@_)
598 unless $_[0] =~ /^Subroutine \S+ redefined/;
ffc705f3 599 };
600 my $code = do {
601 local ($/, @ARGV) = (undef, $old_real_inc_path); <>
602 };
603 $code =~ s/$old_class/$class/g;
604 eval $code;
605 die $@ if $@;
606 }
607
608 while(<$fh>) {
609 chomp;
610 $self->_ext_stmt($class, $_);
611 }
612 $self->_ext_stmt($class,
613 qq|# End of lines loaded from '$old_real_inc_path' |
614 );
615
616 close($fh)
617 or croak "Failed to close $old_real_inc_path: $!";
9e8033c1 618 }
996be9ee 619}
620
621=head2 load
622
623Does the actual schema-construction work.
624
625=cut
626
627sub load {
628 my $self = shift;
629
b97c2c1e 630 $self->_load_tables($self->_tables_list);
631}
632
633=head2 rescan
634
a60b5b8d 635Arguments: schema
636
b97c2c1e 637Rescan the database for newly added tables. Does
a60b5b8d 638not process drops or changes. Returns a list of
639the newly added table monikers.
640
641The schema argument should be the schema class
642or object to be affected. It should probably
643be derived from the original schema_class used
644during L</load>.
b97c2c1e 645
646=cut
647
648sub rescan {
a60b5b8d 649 my ($self, $schema) = @_;
650
651 $self->{schema} = $schema;
7824616e 652 $self->_relbuilder->{schema} = $schema;
b97c2c1e 653
654 my @created;
655 my @current = $self->_tables_list;
656 foreach my $table ($self->_tables_list) {
657 if(!exists $self->{_tables}->{$table}) {
658 push(@created, $table);
659 }
660 }
661
c39e3507 662 my $loaded = $self->_load_tables(@created);
a60b5b8d 663
c39e3507 664 return map { $self->monikers->{$_} } @$loaded;
b97c2c1e 665}
666
7824616e 667sub _relbuilder {
66afce69 668 no warnings 'uninitialized';
7824616e 669 my ($self) = @_;
3fed44ca 670
671 return if $self->{skip_relationships};
672
a8d229ff 673 if ($self->naming->{relationships} eq 'v4') {
674 require DBIx::Class::Schema::Loader::RelBuilder::Compat::v0_040;
675 return $self->{relbuilder} ||=
676 DBIx::Class::Schema::Loader::RelBuilder::Compat::v0_040->new(
677 $self->schema, $self->inflect_plural, $self->inflect_singular
678 );
679 }
680
c8c27020 681 $self->{relbuilder} ||= DBIx::Class::Schema::Loader::RelBuilder->new (
682 $self->schema,
683 $self->inflect_plural,
684 $self->inflect_singular,
685 $self->relationship_attrs,
7824616e 686 );
687}
688
b97c2c1e 689sub _load_tables {
690 my ($self, @tables) = @_;
691
f96ef30f 692 # First, use _tables_list with constraint and exclude
693 # to get a list of tables to operate on
694
695 my $constraint = $self->constraint;
696 my $exclude = $self->exclude;
f96ef30f 697
b97c2c1e 698 @tables = grep { /$constraint/ } @tables if $constraint;
699 @tables = grep { ! /$exclude/ } @tables if $exclude;
f96ef30f 700
b97c2c1e 701 # Save the new tables to the tables list
a60b5b8d 702 foreach (@tables) {
703 $self->{_tables}->{$_} = 1;
704 }
f96ef30f 705
af31090c 706 $self->_make_src_class($_) for @tables;
f96ef30f 707 $self->_setup_src_meta($_) for @tables;
708
e8ad6491 709 if(!$self->skip_relationships) {
181cc907 710 # The relationship loader needs a working schema
af31090c 711 $self->{quiet} = 1;
79193756 712 local $self->{dump_directory} = $self->{temp_directory};
106a976a 713 $self->_reload_classes(\@tables);
e8ad6491 714 $self->_load_relationships($_) for @tables;
af31090c 715 $self->{quiet} = 0;
79193756 716
717 # Remove that temp dir from INC so it doesn't get reloaded
ffc705f3 718 @INC = grep $_ ne $self->dump_directory, @INC;
e8ad6491 719 }
720
f96ef30f 721 $self->_load_external($_)
75451704 722 for map { $self->classes->{$_} } @tables;
f96ef30f 723
106a976a 724 # Reload without unloading first to preserve any symbols from external
725 # packages.
726 $self->_reload_classes(\@tables, 0);
996be9ee 727
5223f24a 728 # Drop temporary cache
729 delete $self->{_cache};
730
c39e3507 731 return \@tables;
996be9ee 732}
733
af31090c 734sub _reload_classes {
106a976a 735 my ($self, $tables, $unload) = @_;
736
737 my @tables = @$tables;
738 $unload = 1 unless defined $unload;
181cc907 739
4daef04f 740 # so that we don't repeat custom sections
741 @INC = grep $_ ne $self->dump_directory, @INC;
742
181cc907 743 $self->_dump_to_dir(map { $self->classes->{$_} } @tables);
e9b8719e 744
745 unshift @INC, $self->dump_directory;
af31090c 746
706ef173 747 my @to_register;
748 my %have_source = map { $_ => $self->schema->source($_) }
749 $self->schema->sources;
750
181cc907 751 for my $table (@tables) {
752 my $moniker = $self->monikers->{$table};
753 my $class = $self->classes->{$table};
0ae6b65d 754
755 {
756 no warnings 'redefine';
757 local *Class::C3::reinitialize = sub {};
758 use warnings;
759
106a976a 760 Class::Unload->unload($class) if $unload;
706ef173 761 my ($source, $resultset_class);
762 if (
763 ($source = $have_source{$moniker})
764 && ($resultset_class = $source->resultset_class)
765 && ($resultset_class ne 'DBIx::Class::ResultSet')
766 ) {
767 my $has_file = Class::Inspector->loaded_filename($resultset_class);
106a976a 768 Class::Unload->unload($resultset_class) if $unload;
769 $self->_reload_class($resultset_class) if $has_file;
0ae6b65d 770 }
106a976a 771 $self->_reload_class($class);
af31090c 772 }
706ef173 773 push @to_register, [$moniker, $class];
774 }
af31090c 775
706ef173 776 Class::C3->reinitialize;
777 for (@to_register) {
778 $self->schema->register_class(@$_);
af31090c 779 }
780}
781
106a976a 782# We use this instead of ensure_class_loaded when there are package symbols we
783# want to preserve.
784sub _reload_class {
785 my ($self, $class) = @_;
786
787 my $class_path = $self->_class_path($class);
788 delete $INC{ $class_path };
f53dcdf0 789
790# kill redefined warnings
502b65d4 791 my $warn_handler = $SIG{__WARN__} || sub { warn @_ };
f53dcdf0 792 local $SIG{__WARN__} = sub {
502b65d4 793 $warn_handler->(@_)
794 unless $_[0] =~ /^Subroutine \S+ redefined/;
f53dcdf0 795 };
106a976a 796 eval "require $class;";
797}
798
996be9ee 799sub _get_dump_filename {
800 my ($self, $class) = (@_);
801
802 $class =~ s{::}{/}g;
803 return $self->dump_directory . q{/} . $class . q{.pm};
804}
805
806sub _ensure_dump_subdirs {
807 my ($self, $class) = (@_);
808
809 my @name_parts = split(/::/, $class);
dd03ee1a 810 pop @name_parts; # we don't care about the very last element,
811 # which is a filename
812
996be9ee 813 my $dir = $self->dump_directory;
7cab3ab7 814 while (1) {
815 if(!-d $dir) {
25328cc4 816 mkdir($dir) or croak "mkdir('$dir') failed: $!";
996be9ee 817 }
7cab3ab7 818 last if !@name_parts;
819 $dir = File::Spec->catdir($dir, shift @name_parts);
996be9ee 820 }
821}
822
823sub _dump_to_dir {
af31090c 824 my ($self, @classes) = @_;
996be9ee 825
fc2b71fd 826 my $schema_class = $self->schema_class;
9c9c2f2b 827 my $schema_base_class = $self->schema_base_class || 'DBIx::Class::Schema';
996be9ee 828
e9b8719e 829 my $target_dir = $self->dump_directory;
af31090c 830 warn "Dumping manual schema for $schema_class to directory $target_dir ...\n"
831 unless $self->{dynamic} or $self->{quiet};
996be9ee 832
7cab3ab7 833 my $schema_text =
834 qq|package $schema_class;\n\n|
b4dcbcc5 835 . qq|# Created by DBIx::Class::Schema::Loader\n|
836 . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|
7cab3ab7 837 . qq|use strict;\nuse warnings;\n\n|
9c9c2f2b 838 . qq|use base '$schema_base_class';\n\n|;
f44ecc2f 839
f44ecc2f 840 if ($self->use_namespaces) {
841 $schema_text .= qq|__PACKAGE__->load_namespaces|;
842 my $namespace_options;
843 for my $attr (qw(result_namespace
844 resultset_namespace
845 default_resultset_class)) {
846 if ($self->$attr) {
847 $namespace_options .= qq| $attr => '| . $self->$attr . qq|',\n|
848 }
849 }
850 $schema_text .= qq|(\n$namespace_options)| if $namespace_options;
851 $schema_text .= qq|;\n|;
852 }
853 else {
854 $schema_text .= qq|__PACKAGE__->load_classes;\n|;
f44ecc2f 855 }
996be9ee 856
1c95b304 857 {
858 local $self->{version_to_dump} = $self->schema_version_to_dump;
859 $self->_write_classfile($schema_class, $schema_text);
860 }
996be9ee 861
2229729e 862 my $result_base_class = $self->result_base_class || 'DBIx::Class::Core';
9c9c2f2b 863
af31090c 864 foreach my $src_class (@classes) {
7cab3ab7 865 my $src_text =
866 qq|package $src_class;\n\n|
b4dcbcc5 867 . qq|# Created by DBIx::Class::Schema::Loader\n|
868 . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|
7cab3ab7 869 . qq|use strict;\nuse warnings;\n\n|
9c9c2f2b 870 . qq|use base '$result_base_class';\n\n|;
996be9ee 871
7cab3ab7 872 $self->_write_classfile($src_class, $src_text);
02356864 873 }
996be9ee 874
af31090c 875 warn "Schema dump completed.\n" unless $self->{dynamic} or $self->{quiet};
876
7cab3ab7 877}
878
79193756 879sub _sig_comment {
880 my ($self, $version, $ts) = @_;
881 return qq|\n\n# Created by DBIx::Class::Schema::Loader|
882 . qq| v| . $version
883 . q| @ | . $ts
884 . qq|\n# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:|;
885}
886
7cab3ab7 887sub _write_classfile {
888 my ($self, $class, $text) = @_;
889
890 my $filename = $self->_get_dump_filename($class);
891 $self->_ensure_dump_subdirs($class);
892
28b4691d 893 if (-f $filename && $self->really_erase_my_files) {
7cab3ab7 894 warn "Deleting existing file '$filename' due to "
af31090c 895 . "'really_erase_my_files' setting\n" unless $self->{quiet};
7cab3ab7 896 unlink($filename);
897 }
898
79193756 899 my ($custom_content, $old_md5, $old_ver, $old_ts) = $self->_get_custom_content($class, $filename);
17ca645f 900
f53dcdf0 901 if ($self->_upgrading_from) {
902 my $old_class = $self->_upgrading_classes->{$class};
903
904 if ($old_class && ($old_class ne $class)) {
905 my $old_filename = $self->_get_dump_filename($old_class);
906
907 my ($old_custom_content) = $self->_get_custom_content(
ffc705f3 908 $old_class, $old_filename, 0 # do not add default comment
f53dcdf0 909 );
910
ffc705f3 911 $old_custom_content =~ s/\n\n# You can replace.*\n1;\n//;
912
913 if ($old_custom_content) {
914 $custom_content =
915 "\n" . $old_custom_content . "\n" . $custom_content;
916 }
f53dcdf0 917
918 unlink $old_filename;
919 }
920 }
921
7cab3ab7 922 $text .= qq|$_\n|
923 for @{$self->{_dump_storage}->{$class} || []};
924
79193756 925 # Check and see if the dump is infact differnt
926
927 my $compare_to;
928 if ($old_md5) {
929 $compare_to = $text . $self->_sig_comment($old_ver, $old_ts);
930
931
932 if (Digest::MD5::md5_base64($compare_to) eq $old_md5) {
933 return;
934 }
935 }
936
937 $text .= $self->_sig_comment(
01012543 938 $self->version_to_dump,
79193756 939 POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime)
940 );
7cab3ab7 941
942 open(my $fh, '>', $filename)
943 or croak "Cannot open '$filename' for writing: $!";
944
945 # Write the top half and its MD5 sum
a4476f41 946 print $fh $text . Digest::MD5::md5_base64($text) . "\n";
7cab3ab7 947
948 # Write out anything loaded via external partial class file in @INC
949 print $fh qq|$_\n|
950 for @{$self->{_ext_storage}->{$class} || []};
951
1eea4fb1 952 # Write out any custom content the user has added
7cab3ab7 953 print $fh $custom_content;
954
955 close($fh)
e9b8719e 956 or croak "Error closing '$filename': $!";
7cab3ab7 957}
958
79193756 959sub _default_custom_content {
960 return qq|\n\n# You can replace this text with custom|
961 . qq| content, and it will be preserved on regeneration|
962 . qq|\n1;\n|;
963}
964
7cab3ab7 965sub _get_custom_content {
ffc705f3 966 my ($self, $class, $filename, $add_default) = @_;
967
968 $add_default = 1 unless defined $add_default;
7cab3ab7 969
79193756 970 return ($self->_default_custom_content) if ! -f $filename;
971
7cab3ab7 972 open(my $fh, '<', $filename)
973 or croak "Cannot open '$filename' for reading: $!";
974
975 my $mark_re =
419a2eeb 976 qr{^(# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:)([A-Za-z0-9/+]{22})\n};
7cab3ab7 977
7cab3ab7 978 my $buffer = '';
79193756 979 my ($md5, $ts, $ver);
7cab3ab7 980 while(<$fh>) {
79193756 981 if(!$md5 && /$mark_re/) {
982 $md5 = $2;
983 my $line = $1;
984
985 # Pull out the previous version and timestamp
986 ($ver, $ts) = $buffer =~ m/# Created by DBIx::Class::Schema::Loader v(.*?) @ (.*?)$/s;
987
988 $buffer .= $line;
b4cc5793 989 croak "Checksum mismatch in '$filename', the auto-generated part of the file has been modified outside of this loader. Aborting.\nIf you want to overwrite these modifications, set the 'overwrite_modifications' loader option.\n"
639a1367 990 if !$self->overwrite_modifications && Digest::MD5::md5_base64($buffer) ne $md5;
7cab3ab7 991
992 $buffer = '';
993 }
994 else {
995 $buffer .= $_;
996 }
996be9ee 997 }
998
28b4691d 999 croak "Cannot not overwrite '$filename' without 'really_erase_my_files',"
419a2eeb 1000 . " it does not appear to have been generated by Loader"
79193756 1001 if !$md5;
5ef3c771 1002
79193756 1003 # Default custom content:
ffc705f3 1004 $buffer ||= $self->_default_custom_content if $add_default;
5ef3c771 1005
79193756 1006 return ($buffer, $md5, $ver, $ts);
996be9ee 1007}
1008
1009sub _use {
1010 my $self = shift;
1011 my $target = shift;
1012
1013 foreach (@_) {
cb54990b 1014 warn "$target: use $_;" if $self->debug;
996be9ee 1015 $self->_raw_stmt($target, "use $_;");
996be9ee 1016 }
1017}
1018
1019sub _inject {
1020 my $self = shift;
1021 my $target = shift;
1022 my $schema_class = $self->schema_class;
1023
af31090c 1024 my $blist = join(q{ }, @_);
1025 warn "$target: use base qw/ $blist /;" if $self->debug && @_;
1026 $self->_raw_stmt($target, "use base qw/ $blist /;") if @_;
996be9ee 1027}
1028
f96ef30f 1029# Create class with applicable bases, setup monikers, etc
1030sub _make_src_class {
1031 my ($self, $table) = @_;
996be9ee 1032
a13b2803 1033 my $schema = $self->schema;
1034 my $schema_class = $self->schema_class;
996be9ee 1035
f96ef30f 1036 my $table_moniker = $self->_table2moniker($table);
f44ecc2f 1037 my @result_namespace = ($schema_class);
1038 if ($self->use_namespaces) {
1039 my $result_namespace = $self->result_namespace || 'Result';
1040 if ($result_namespace =~ /^\+(.*)/) {
1041 # Fully qualified namespace
1042 @result_namespace = ($1)
1043 }
1044 else {
1045 # Relative namespace
1046 push @result_namespace, $result_namespace;
1047 }
1048 }
1049 my $table_class = join(q{::}, @result_namespace, $table_moniker);
996be9ee 1050
f53dcdf0 1051 if (my $upgrading_v = $self->_upgrading_from) {
1052 local $self->naming->{monikers} = $upgrading_v;
1053
1054 my $old_class = join(q{::}, @result_namespace,
1055 $self->_table2moniker($table));
1056
1057 $self->_upgrading_classes->{$table_class} = $old_class;
1058 }
1059
f96ef30f 1060 my $table_normalized = lc $table;
1061 $self->classes->{$table} = $table_class;
1062 $self->classes->{$table_normalized} = $table_class;
1063 $self->monikers->{$table} = $table_moniker;
1064 $self->monikers->{$table_normalized} = $table_moniker;
996be9ee 1065
f96ef30f 1066 $self->_use ($table_class, @{$self->additional_classes});
af31090c 1067 $self->_inject($table_class, @{$self->left_base_classes});
996be9ee 1068
2229729e 1069 if (my @components = @{ $self->components }) {
1070 $self->_dbic_stmt($table_class, 'load_components', @components);
1071 }
996be9ee 1072
f96ef30f 1073 $self->_dbic_stmt($table_class, 'load_resultset_components', @{$self->resultset_components})
1074 if @{$self->resultset_components};
af31090c 1075 $self->_inject($table_class, @{$self->additional_base_classes});
f96ef30f 1076}
996be9ee 1077
af31090c 1078# Set up metadata (cols, pks, etc)
f96ef30f 1079sub _setup_src_meta {
1080 my ($self, $table) = @_;
996be9ee 1081
f96ef30f 1082 my $schema = $self->schema;
1083 my $schema_class = $self->schema_class;
a13b2803 1084
f96ef30f 1085 my $table_class = $self->classes->{$table};
1086 my $table_moniker = $self->monikers->{$table};
996be9ee 1087
ff30991a 1088 my $table_name = $table;
1089 my $name_sep = $self->schema->storage->sql_maker->name_sep;
1090
c177d483 1091 if ($name_sep && $table_name =~ /\Q$name_sep\E/) {
ff30991a 1092 $table_name = \ $self->_quote_table_name($table_name);
1093 }
1094
1095 $self->_dbic_stmt($table_class,'table',$table_name);
996be9ee 1096
f96ef30f 1097 my $cols = $self->_table_columns($table);
1098 my $col_info;
1099 eval { $col_info = $self->_columns_info_for($table) };
1100 if($@) {
1101 $self->_dbic_stmt($table_class,'add_columns',@$cols);
1102 }
1103 else {
0906d55b 1104 if ($self->_is_case_sensitive) {
1105 for my $col (keys %$col_info) {
1106 $col_info->{$col}{accessor} = lc $col
1107 if $col ne lc($col);
1108 }
1109 } else {
1110 $col_info = { map { lc($_), $col_info->{$_} } keys %$col_info };
c9373b79 1111 }
1112
e7213f4f 1113 my $fks = $self->_table_fk_info($table);
565335e6 1114
e7213f4f 1115 for my $fkdef (@$fks) {
1116 for my $col (@{ $fkdef->{local_columns} }) {
565335e6 1117 $col_info->{$col}{is_foreign_key} = 1;
e7213f4f 1118 }
1119 }
f96ef30f 1120 $self->_dbic_stmt(
1121 $table_class,
1122 'add_columns',
565335e6 1123 map { $_, ($col_info->{$_}||{}) } @$cols
f96ef30f 1124 );
996be9ee 1125 }
1126
d70c335f 1127 my %uniq_tag; # used to eliminate duplicate uniqs
1128
f96ef30f 1129 my $pks = $self->_table_pk_info($table) || [];
1130 @$pks ? $self->_dbic_stmt($table_class,'set_primary_key',@$pks)
1131 : carp("$table has no primary key");
d70c335f 1132 $uniq_tag{ join("\0", @$pks) }++ if @$pks; # pk is a uniq
996be9ee 1133
f96ef30f 1134 my $uniqs = $self->_table_uniq_info($table) || [];
d70c335f 1135 for (@$uniqs) {
1136 my ($name, $cols) = @$_;
1137 next if $uniq_tag{ join("\0", @$cols) }++; # skip duplicates
1138 $self->_dbic_stmt($table_class,'add_unique_constraint', $name, $cols);
1139 }
1140
996be9ee 1141}
1142
1143=head2 tables
1144
1145Returns a sorted list of loaded tables, using the original database table
1146names.
1147
1148=cut
1149
1150sub tables {
1151 my $self = shift;
1152
b97c2c1e 1153 return keys %{$self->_tables};
996be9ee 1154}
1155
1156# Make a moniker from a table
c39e403e 1157sub _default_table2moniker {
66afce69 1158 no warnings 'uninitialized';
c39e403e 1159 my ($self, $table) = @_;
1160
a8d229ff 1161 if ($self->naming->{monikers} eq 'v4') {
1162 return join '', map ucfirst, split /[\W_]+/, lc $table;
1163 }
1164
c39e403e 1165 return join '', map ucfirst, split /[\W_]+/,
1166 Lingua::EN::Inflect::Number::to_S(lc $table);
1167}
1168
996be9ee 1169sub _table2moniker {
1170 my ( $self, $table ) = @_;
1171
1172 my $moniker;
1173
1174 if( ref $self->moniker_map eq 'HASH' ) {
1175 $moniker = $self->moniker_map->{$table};
1176 }
1177 elsif( ref $self->moniker_map eq 'CODE' ) {
1178 $moniker = $self->moniker_map->($table);
1179 }
1180
c39e403e 1181 $moniker ||= $self->_default_table2moniker($table);
996be9ee 1182
1183 return $moniker;
1184}
1185
1186sub _load_relationships {
e8ad6491 1187 my ($self, $table) = @_;
996be9ee 1188
e8ad6491 1189 my $tbl_fk_info = $self->_table_fk_info($table);
1190 foreach my $fkdef (@$tbl_fk_info) {
1191 $fkdef->{remote_source} =
1192 $self->monikers->{delete $fkdef->{remote_table}};
996be9ee 1193 }
26f1c8c9 1194 my $tbl_uniq_info = $self->_table_uniq_info($table);
996be9ee 1195
e8ad6491 1196 my $local_moniker = $self->monikers->{$table};
7824616e 1197 my $rel_stmts = $self->_relbuilder->generate_code($local_moniker, $tbl_fk_info, $tbl_uniq_info);
996be9ee 1198
996be9ee 1199 foreach my $src_class (sort keys %$rel_stmts) {
1200 my $src_stmts = $rel_stmts->{$src_class};
1201 foreach my $stmt (@$src_stmts) {
1202 $self->_dbic_stmt($src_class,$stmt->{method},@{$stmt->{args}});
1203 }
1204 }
1205}
1206
1207# Overload these in driver class:
1208
1209# Returns an arrayref of column names
1210sub _table_columns { croak "ABSTRACT METHOD" }
1211
1212# Returns arrayref of pk col names
1213sub _table_pk_info { croak "ABSTRACT METHOD" }
1214
1215# Returns an arrayref of uniqs [ [ foo => [ col1, col2 ] ], [ bar => [ ... ] ] ]
1216sub _table_uniq_info { croak "ABSTRACT METHOD" }
1217
1218# Returns an arrayref of foreign key constraints, each
1219# being a hashref with 3 keys:
1220# local_columns (arrayref), remote_columns (arrayref), remote_table
1221sub _table_fk_info { croak "ABSTRACT METHOD" }
1222
1223# Returns an array of lower case table names
1224sub _tables_list { croak "ABSTRACT METHOD" }
1225
1226# Execute a constructive DBIC class method, with debug/dump_to_dir hooks.
1227sub _dbic_stmt {
bf654ab9 1228 my $self = shift;
1229 my $class = shift;
996be9ee 1230 my $method = shift;
bf654ab9 1231
1232 # generate the pod for this statement, storing it with $self->_pod
1233 $self->_make_pod( $class, $method, @_ );
1234
1235 my $args = dump(@_);
1236 $args = '(' . $args . ')' if @_ < 2;
1237 my $stmt = $method . $args . q{;};
1238
1239 warn qq|$class\->$stmt\n| if $self->debug;
1240 $self->_raw_stmt($class, '__PACKAGE__->' . $stmt);
1241 return;
1242}
1243
1244# generates the accompanying pod for a DBIC class method statement,
1245# storing it with $self->_pod
1246sub _make_pod {
1247 my $self = shift;
1248 my $class = shift;
1249 my $method = shift;
1250
fbcfebdd 1251 if ( $method eq 'table' ) {
1252 my ($table) = @_;
1253 $self->_pod( $class, "=head1 NAME" );
1254 my $table_descr = $class;
1255 if ( $self->can('_table_comment') ) {
1256 my $comment = $self->_table_comment($table);
1257 $table_descr .= " - " . $comment if $comment;
1258 }
1259 $self->{_class2table}{ $class } = $table;
1260 $self->_pod( $class, $table_descr );
1261 $self->_pod_cut( $class );
1262 } elsif ( $method eq 'add_columns' ) {
1263 $self->_pod( $class, "=head1 ACCESSORS" );
79a00530 1264 my $col_counter = 0;
1265 my @cols = @_;
1266 while( my ($name,$attrs) = splice @cols,0,2 ) {
1267 $col_counter++;
1268 $self->_pod( $class, '=head2 ' . $name );
1269 $self->_pod( $class,
1270 join "\n", map {
1271 my $s = $attrs->{$_};
1272 $s = !defined $s ? 'undef' :
1273 length($s) == 0 ? '(empty string)' :
1274 $s;
1275
1276 " $_: $s"
1277 } sort keys %$attrs,
1278 );
1279
1280 if( $self->can('_column_comment')
1281 and my $comment = $self->_column_comment( $self->{_class2table}{$class}, $col_counter)
1282 ) {
1283 $self->_pod( $class, $comment );
1284 }
fbcfebdd 1285 }
1286 $self->_pod_cut( $class );
1287 } elsif ( $method =~ /^(belongs_to|has_many|might_have)$/ ) {
1288 $self->_pod( $class, "=head1 RELATIONS" ) unless $self->{_relations_started} { $class } ;
1289 my ( $accessor, $rel_class ) = @_;
1290 $self->_pod( $class, "=head2 $accessor" );
1291 $self->_pod( $class, 'Type: ' . $method );
1292 $self->_pod( $class, "Related object: L<$rel_class>" );
1293 $self->_pod_cut( $class );
1294 $self->{_relations_started} { $class } = 1;
1295 }
996be9ee 1296}
1297
fbcfebdd 1298# Stores a POD documentation
1299sub _pod {
1300 my ($self, $class, $stmt) = @_;
1301 $self->_raw_stmt( $class, "\n" . $stmt );
1302}
1303
1304sub _pod_cut {
1305 my ($self, $class ) = @_;
1306 $self->_raw_stmt( $class, "\n=cut\n" );
1307}
1308
1309
996be9ee 1310# Store a raw source line for a class (for dumping purposes)
1311sub _raw_stmt {
1312 my ($self, $class, $stmt) = @_;
af31090c 1313 push(@{$self->{_dump_storage}->{$class}}, $stmt);
996be9ee 1314}
1315
7cab3ab7 1316# Like above, but separately for the externally loaded stuff
1317sub _ext_stmt {
1318 my ($self, $class, $stmt) = @_;
af31090c 1319 push(@{$self->{_ext_storage}->{$class}}, $stmt);
7cab3ab7 1320}
1321
565335e6 1322sub _quote_table_name {
1323 my ($self, $table) = @_;
1324
1325 my $qt = $self->schema->storage->sql_maker->quote_char;
1326
c177d483 1327 return $table unless $qt;
1328
565335e6 1329 if (ref $qt) {
1330 return $qt->[0] . $table . $qt->[1];
1331 }
1332
1333 return $qt . $table . $qt;
1334}
1335
1336sub _is_case_sensitive { 0 }
1337
ffc705f3 1338# remove the dump dir from @INC on destruction
1339sub DESTROY {
1340 my $self = shift;
1341
1342 @INC = grep $_ ne $self->dump_directory, @INC;
1343}
1344
996be9ee 1345=head2 monikers
1346
8f9d7ce5 1347Returns a hashref of loaded table to moniker mappings. There will
996be9ee 1348be two entries for each table, the original name and the "normalized"
1349name, in the case that the two are different (such as databases
1350that like uppercase table names, or preserve your original mixed-case
1351definitions, or what-have-you).
1352
1353=head2 classes
1354
8f9d7ce5 1355Returns a hashref of table to class mappings. In some cases it will
996be9ee 1356contain multiple entries per table for the original and normalized table
1357names, as above in L</monikers>.
1358
1359=head1 SEE ALSO
1360
1361L<DBIx::Class::Schema::Loader>
1362
be80bba7 1363=head1 AUTHOR
1364
9cc8e7e1 1365See L<DBIx::Class::Schema::Loader/AUTHOR> and L<DBIx::Class::Schema::Loader/CONTRIBUTORS>.
be80bba7 1366
1367=head1 LICENSE
1368
1369This library is free software; you can redistribute it and/or modify it under
1370the same terms as Perl itself.
1371
996be9ee 1372=cut
1373
13741;