document use_moose option
[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/;
f170d55b 6use namespace::autoclean;
996be9ee 7use Class::C3;
fa994d3c 8use Carp::Clan qw/^DBIx::Class/;
996be9ee 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//;
ecf930e6 16use Lingua::EN::Inflect::Phrase qw//;
af31090c 17use File::Temp qw//;
18use Class::Unload;
8048320c 19use Class::Inspector ();
f170d55b 20use Data::Dumper::Concise;
21use Scalar::Util 'looks_like_number';
b0d2b300 22use File::Slurp 'slurp';
cc4f11a2 23use DBIx::Class::Schema::Loader::Utils 'split_name';
996be9ee 24require DBIx::Class;
25
6b1d4f76 26our $VERSION = '0.07001';
32f784fc 27
3d95f9ff 28__PACKAGE__->mk_group_ro_accessors('simple', qw/
996be9ee 29 schema
30 schema_class
31
32 exclude
33 constraint
34 additional_classes
35 additional_base_classes
36 left_base_classes
37 components
38 resultset_components
59cfa251 39 skip_relationships
0ca61324 40 skip_load_external
996be9ee 41 moniker_map
b639d969 42 custom_column_info
996be9ee 43 inflect_singular
44 inflect_plural
45 debug
46 dump_directory
d65cda9e 47 dump_overwrite
28b4691d 48 really_erase_my_files
f44ecc2f 49 resultset_namespace
50 default_resultset_class
9c9c2f2b 51 schema_base_class
52 result_base_class
dcaf302a 53 use_moose
639a1367 54 overwrite_modifications
996be9ee 55
c8c27020 56 relationship_attrs
57
996be9ee 58 db_schema
59 _tables
60 classes
f53dcdf0 61 _upgrading_classes
996be9ee 62 monikers
106a976a 63 dynamic
a8d229ff 64 naming
42e785fa 65 datetime_timezone
66 datetime_locale
73099af4 67 config_file
71a6e88a 68 loader_class
69219349 69 qualify_objects
65e705c3 70/);
71
996be9ee 72
3d95f9ff 73__PACKAGE__->mk_group_accessors('simple', qw/
01012543 74 version_to_dump
1c95b304 75 schema_version_to_dump
f53dcdf0 76 _upgrading_from
f22644d7 77 _upgrading_from_load_classes
a4b94090 78 _downgrading_to_load_classes
540a8149 79 _rewriting_result_namespace
f22644d7 80 use_namespaces
540a8149 81 result_namespace
492dce8d 82 generate_pod
43b982ea 83 pod_comment_mode
84 pod_comment_spillover_length
bc1cb85e 85 preserve_case
01012543 86/);
87
996be9ee 88=head1 NAME
89
90DBIx::Class::Schema::Loader::Base - Base DBIx::Class::Schema::Loader Implementation.
91
92=head1 SYNOPSIS
93
94See L<DBIx::Class::Schema::Loader>
95
96=head1 DESCRIPTION
97
98This is the base class for the storage-specific C<DBIx::Class::Schema::*>
99classes, and implements the common functionality between them.
100
101=head1 CONSTRUCTOR OPTIONS
102
103These constructor options are the base options for
29ddb54c 104L<DBIx::Class::Schema::Loader/loader_options>. Available constructor options are:
3953cbee 105
59cfa251 106=head2 skip_relationships
996be9ee 107
59cfa251 108Skip setting up relationships. The default is to attempt the loading
109of relationships.
996be9ee 110
0ca61324 111=head2 skip_load_external
112
113Skip loading of other classes in @INC. The default is to merge all other classes
114with the same name found in @INC into the schema file we are creating.
115
9a95164d 116=head2 naming
117
ecf930e6 118Static schemas (ones dumped to disk) will, by default, use the new-style
9a95164d 119relationship names and singularized Results, unless you're overwriting an
ecf930e6 120existing dump made by an older version of L<DBIx::Class::Schema::Loader>, in
121which case the backward compatible RelBuilder will be activated, and the
122appropriate monikerization used.
9a95164d 123
124Specifying
125
ecf930e6 126 naming => 'current'
9a95164d 127
128will disable the backward-compatible RelBuilder and use
129the new-style relationship names along with singularized Results, even when
130overwriting a dump made with an earlier version.
131
132The option also takes a hashref:
133
2a1ff2ee 134 naming => { relationships => 'v7', monikers => 'v7' }
a8d229ff 135
136The keys are:
137
138=over 4
139
140=item relationships
141
142How to name relationship accessors.
143
144=item monikers
145
146How to name Result classes.
147
f3a657ef 148=item column_accessors
149
150How to name column accessors in Result classes.
151
a8d229ff 152=back
9a95164d 153
154The values can be:
155
156=over 4
157
158=item current
159
ecf930e6 160Latest style, whatever that happens to be.
161
162=item v4
163
164Unsingularlized monikers, C<has_many> only relationships with no _id stripping.
9a95164d 165
166=item v5
167
ecf930e6 168Monikers singularized as whole words, C<might_have> relationships for FKs on
169C<UNIQUE> constraints, C<_id> stripping for belongs_to relationships.
9a95164d 170
ecf930e6 171Some of the C<_id> stripping edge cases in C<0.05003> have been reverted for
172the v5 RelBuilder.
173
174=item v6
9a95164d 175
19b7d71c 176All monikers and relationships are inflected using
177L<Lingua::EN::Inflect::Phrase>, and there is more aggressive C<_id> stripping
178from relationship names.
ecf930e6 179
180In general, there is very little difference between v5 and v6 schemas.
9a95164d 181
9990e58f 182=item v7
183
184This mode is identical to C<v6> mode, except that monikerization of CamelCase
185table names is also done correctly.
186
0c1d5b47 187CamelCase column names in case-preserving mode will also be handled correctly
188for relationship name inflection. See L</preserve_case>.
19b7d71c 189
f3a657ef 190In this mode, CamelCase L</column_accessors> are normalized based on case
191transition instead of just being lowercased, so C<FooId> becomes C<foo_id>.
192
19b7d71c 193If you don't have any CamelCase table or column names, you can upgrade without
194breaking any of your code.
9990e58f 195
9a95164d 196=back
197
198Dynamic schemas will always default to the 0.04XXX relationship names and won't
199singularize Results for backward compatibility, to activate the new RelBuilder
200and singularization put this in your C<Schema.pm> file:
201
202 __PACKAGE__->naming('current');
203
c9cf9b4d 204Or if you prefer to use 0.07XXX features but insure that nothing breaks in the
9a95164d 205next major version upgrade:
206
c9cf9b4d 207 __PACKAGE__->naming('v7');
9a95164d 208
492dce8d 209=head2 generate_pod
210
211By default POD will be generated for columns and relationships, using database
7f2de014 212metadata for the text if available and supported.
213
214Reading database metadata (e.g. C<COMMENT ON TABLE some_table ...>) is only
215supported for Postgres right now.
492dce8d 216
217Set this to C<0> to turn off all POD generation.
218
43b982ea 219=head2 pod_comment_mode
220
f7976fea 221Controls where table comments appear in the generated POD. Smaller table
222comments are appended to the C<NAME> section of the documentation, and larger
223ones are inserted into C<DESCRIPTION> instead. You can force a C<DESCRIPTION>
224section to be generated with the comment always, only use C<NAME>, or choose
225the length threshold at which the comment is forced into the description.
43b982ea 226
34896b5e 227=over 4
228
229=item name
230
231Use C<NAME> section only.
232
233=item description
234
235Force C<DESCRIPTION> always.
236
237=item auto
238
239Use C<DESCRIPTION> if length > L</pod_comment_spillover_length>, this is the
240default.
241
242=back
43b982ea 243
244=head2 pod_comment_spillover_length
245
246When pod_comment_mode is set to C<auto>, this is the length of the comment at
247which it will be forced into a separate description section.
248
249The default is C<60>
250
c8c27020 251=head2 relationship_attrs
252
253Hashref of attributes to pass to each generated relationship, listed
254by type. Also supports relationship type 'all', containing options to
255pass to all generated relationships. Attributes set for more specific
256relationship types override those set in 'all'.
257
258For example:
259
260 relationship_attrs => {
6818ce9f 261 belongs_to => { is_deferrable => 1 },
c8c27020 262 },
263
6818ce9f 264use this to make your foreign key constraints DEFERRABLE.
c8c27020 265
996be9ee 266=head2 debug
267
268If set to true, each constructive L<DBIx::Class> statement the loader
269decides to execute will be C<warn>-ed before execution.
270
d65cda9e 271=head2 db_schema
272
273Set the name of the schema to load (schema in the sense that your database
274vendor means it). Does not currently support loading more than one schema
275name.
276
996be9ee 277=head2 constraint
278
279Only load tables matching regex. Best specified as a qr// regex.
280
281=head2 exclude
282
283Exclude tables matching regex. Best specified as a qr// regex.
284
285=head2 moniker_map
286
8f9d7ce5 287Overrides the default table name to moniker translation. Can be either
288a hashref of table keys and moniker values, or a coderef for a translator
996be9ee 289function taking a single scalar table name argument and returning
290a scalar moniker. If the hash entry does not exist, or the function
291returns a false value, the code falls back to default behavior
292for that table name.
293
9990e58f 294The default behavior is to split on case transition and non-alphanumeric
295boundaries, singularize the resulting phrase, then join the titlecased words
296together. Examples:
996be9ee 297
9990e58f 298 Table Name | Moniker Name
299 ---------------------------------
300 luser | Luser
301 luser_group | LuserGroup
302 luser-opts | LuserOpt
303 stations_visited | StationVisited
304 routeChange | RouteChange
996be9ee 305
306=head2 inflect_plural
307
308Just like L</moniker_map> above (can be hash/code-ref, falls back to default
309if hash key does not exist or coderef returns false), but acts as a map
310for pluralizing relationship names. The default behavior is to utilize
311L<Lingua::EN::Inflect::Number/to_PL>.
312
313=head2 inflect_singular
314
315As L</inflect_plural> above, but for singularizing relationship names.
316Default behavior is to utilize L<Lingua::EN::Inflect::Number/to_S>.
317
9c9c2f2b 318=head2 schema_base_class
319
320Base class for your schema classes. Defaults to 'DBIx::Class::Schema'.
321
322=head2 result_base_class
323
2229729e 324Base class for your table classes (aka result classes). Defaults to
325'DBIx::Class::Core'.
9c9c2f2b 326
996be9ee 327=head2 additional_base_classes
328
329List of additional base classes all of your table classes will use.
330
331=head2 left_base_classes
332
333List of additional base classes all of your table classes will use
334that need to be leftmost.
335
336=head2 additional_classes
337
338List of additional classes which all of your table classes will use.
339
340=head2 components
341
342List of additional components to be loaded into all of your table
eccc52fe 343classes. A good example would be
344L<InflateColumn::DateTime|DBIx::Class::InflateColumn::DateTime>
996be9ee 345
346=head2 resultset_components
347
8f9d7ce5 348List of additional ResultSet components to be loaded into your table
996be9ee 349classes. A good example would be C<AlwaysRS>. Component
350C<ResultSetManager> will be automatically added to the above
351C<components> list if this option is set.
352
f44ecc2f 353=head2 use_namespaces
354
f22644d7 355This is now the default, to go back to L<DBIx::Class::Schema/load_classes> pass
356a C<0>.
357
f44ecc2f 358Generate result class names suitable for
359L<DBIx::Class::Schema/load_namespaces> and call that instead of
360L<DBIx::Class::Schema/load_classes>. When using this option you can also
361specify any of the options for C<load_namespaces> (i.e. C<result_namespace>,
362C<resultset_namespace>, C<default_resultset_class>), and they will be added
363to the call (and the generated result class names adjusted appropriately).
364
996be9ee 365=head2 dump_directory
366
367This option is designed to be a tool to help you transition from this
368loader to a manually-defined schema when you decide it's time to do so.
369
370The value of this option is a perl libdir pathname. Within
371that directory this module will create a baseline manual
372L<DBIx::Class::Schema> module set, based on what it creates at runtime
373in memory.
374
375The created schema class will have the same classname as the one on
376which you are setting this option (and the ResultSource classes will be
7cab3ab7 377based on this name as well).
996be9ee 378
8f9d7ce5 379Normally you wouldn't hard-code this setting in your schema class, as it
996be9ee 380is meant for one-time manual usage.
381
382See L<DBIx::Class::Schema::Loader/dump_to_dir> for examples of the
383recommended way to access this functionality.
384
d65cda9e 385=head2 dump_overwrite
386
28b4691d 387Deprecated. See L</really_erase_my_files> below, which does *not* mean
388the same thing as the old C<dump_overwrite> setting from previous releases.
389
390=head2 really_erase_my_files
391
7cab3ab7 392Default false. If true, Loader will unconditionally delete any existing
393files before creating the new ones from scratch when dumping a schema to disk.
394
395The default behavior is instead to only replace the top portion of the
396file, up to and including the final stanza which contains
397C<# DO NOT MODIFY THIS OR ANYTHING ABOVE!>
398leaving any customizations you placed after that as they were.
399
28b4691d 400When C<really_erase_my_files> is not set, if the output file already exists,
7cab3ab7 401but the aforementioned final stanza is not found, or the checksum
402contained there does not match the generated contents, Loader will
403croak and not touch the file.
d65cda9e 404
28b4691d 405You should really be using version control on your schema classes (and all
406of the rest of your code for that matter). Don't blame me if a bug in this
407code wipes something out when it shouldn't have, you've been warned.
408
639a1367 409=head2 overwrite_modifications
410
411Default false. If false, when updating existing files, Loader will
412refuse to modify any Loader-generated code that has been modified
413since its last run (as determined by the checksum Loader put in its
414comment lines).
415
416If true, Loader will discard any manual modifications that have been
417made to Loader-generated code.
418
419Again, you should be using version control on your schema classes. Be
420careful with this option.
421
3a368709 422=head2 custom_column_info
423
d67d058e 424Hook for adding extra attributes to the
425L<column_info|DBIx::Class::ResultSource/column_info> for a column.
426
427Must be a coderef that returns a hashref with the extra attributes.
428
429Receives the table name, column name and column_info.
430
431For example:
432
433 custom_column_info => sub {
434 my ($table_name, $column_name, $column_info) = @_;
435
436 if ($column_name eq 'dog' && $column_info->{default_value} eq 'snoopy') {
437 return { is_snoopy => 1 };
438 }
439 },
3a368709 440
d67d058e 441This attribute can also be used to set C<inflate_datetime> on a non-datetime
442column so it also receives the L</datetime_timezone> and/or L</datetime_locale>.
3a368709 443
42e785fa 444=head2 datetime_timezone
445
d67d058e 446Sets the timezone attribute for L<DBIx::Class::InflateColumn::DateTime> for all
447columns with the DATE/DATETIME/TIMESTAMP data_types.
42e785fa 448
449=head2 datetime_locale
450
d67d058e 451Sets the locale attribute for L<DBIx::Class::InflateColumn::DateTime> for all
452columns with the DATE/DATETIME/TIMESTAMP data_types.
42e785fa 453
7ffafa37 454=head2 config_file
73099af4 455
456File in Perl format, which should return a HASH reference, from which to read
457loader options.
458
7ffafa37 459=head2 preserve_case
bc1cb85e 460
461Usually column names are lowercased, to make them easier to work with in
462L<DBIx::Class>. This option lets you turn this behavior off, if the driver
463supports it.
464
465Drivers for case sensitive databases like Sybase ASE or MSSQL with a
466case-sensitive collation will turn this option on unconditionally.
467
468Currently the drivers for SQLite, mysql, MSSQL and Firebird/InterBase support
469setting this option.
470
7ffafa37 471=head2 qualify_objects
69219349 472
473Set to true to prepend the L</db_schema> to table names for C<<
474__PACKAGE__->table >> calls, and to some other things like Oracle sequences.
475
7d0ea6b9 476=head2 use_moose
477
478Creates Schema and Result classes that use L<Moose>, L<MooseX::NonMoose> and
479L<namespace::autoclean>. The default custom content also makes the classes
480immutable.
481
482It is safe to upgrade your existing Schema to this option.
483
996be9ee 484=head1 METHODS
485
486None of these methods are intended for direct invocation by regular
d67d058e 487users of L<DBIx::Class::Schema::Loader>. Some are proxied via
488L<DBIx::Class::Schema::Loader>.
996be9ee 489
490=cut
491
9990e58f 492my $CURRENT_V = 'v7';
8048320c 493
c5df7397 494my @CLASS_ARGS = qw(
8048320c 495 schema_base_class result_base_class additional_base_classes
496 left_base_classes additional_classes components resultset_components
497);
66afce69 498
996be9ee 499# ensure that a peice of object data is a valid arrayref, creating
500# an empty one or encapsulating whatever's there.
501sub _ensure_arrayref {
502 my $self = shift;
503
504 foreach (@_) {
505 $self->{$_} ||= [];
506 $self->{$_} = [ $self->{$_} ]
507 unless ref $self->{$_} eq 'ARRAY';
508 }
509}
510
511=head2 new
512
513Constructor for L<DBIx::Class::Schema::Loader::Base>, used internally
514by L<DBIx::Class::Schema::Loader>.
515
516=cut
517
518sub new {
519 my ( $class, %args ) = @_;
520
521 my $self = { %args };
522
523 bless $self => $class;
524
73099af4 525 if (my $config_file = $self->config_file) {
526 my $config_opts = do $config_file;
527
528 croak "Error reading config from $config_file: $@" if $@;
529
530 croak "Config file $config_file must be a hashref" unless ref($config_opts) eq 'HASH';
531
532 while (my ($k, $v) = each %$config_opts) {
533 $self->{$k} = $v unless exists $self->{$k};
534 }
535 }
536
996be9ee 537 $self->_ensure_arrayref(qw/additional_classes
538 additional_base_classes
539 left_base_classes
540 components
541 resultset_components
542 /);
543
8048320c 544 $self->_validate_class_args;
545
c9cf9b4d 546 if ($self->use_moose) {
547 eval <<'EOF';
548package __DBICSL__DUMMY;
549use Moose;
550use MooseX::NonMoose;
551use namespace::autoclean;
552EOF
553 if ($@) {
554 die sprintf "You must install the following CPAN modules to enable the use_moose option: %s.\n",
555 "Moose, MooseX::NonMoose and namespace::autoclean";
556 }
557 }
558
996be9ee 559 push(@{$self->{components}}, 'ResultSetManager')
560 if @{$self->{resultset_components}};
561
562 $self->{monikers} = {};
563 $self->{classes} = {};
f53dcdf0 564 $self->{_upgrading_classes} = {};
996be9ee 565
996be9ee 566 $self->{schema_class} ||= ( ref $self->{schema} || $self->{schema} );
567 $self->{schema} ||= $self->{schema_class};
568
28b4691d 569 croak "dump_overwrite is deprecated. Please read the"
570 . " DBIx::Class::Schema::Loader::Base documentation"
571 if $self->{dump_overwrite};
572
af31090c 573 $self->{dynamic} = ! $self->{dump_directory};
79193756 574 $self->{temp_directory} ||= File::Temp::tempdir( 'dbicXXXX',
af31090c 575 TMPDIR => 1,
576 CLEANUP => 1,
577 );
578
79193756 579 $self->{dump_directory} ||= $self->{temp_directory};
580
01012543 581 $self->version_to_dump($DBIx::Class::Schema::Loader::VERSION);
1c95b304 582 $self->schema_version_to_dump($DBIx::Class::Schema::Loader::VERSION);
01012543 583
66afce69 584 if ((not ref $self->naming) && defined $self->naming) {
9cc8e7e1 585 my $naming_ver = $self->naming;
a8d229ff 586 $self->{naming} = {
587 relationships => $naming_ver,
588 monikers => $naming_ver,
f3a657ef 589 column_accessors => $naming_ver,
a8d229ff 590 };
591 }
592
66afce69 593 if ($self->naming) {
594 for (values %{ $self->naming }) {
c5df7397 595 $_ = $CURRENT_V if $_ eq 'current';
66afce69 596 }
597 }
598 $self->{naming} ||= {};
599
d67d058e 600 if ($self->custom_column_info && ref $self->custom_column_info ne 'CODE') {
601 croak 'custom_column_info must be a CODE ref';
602 }
603
7824616e 604 $self->_check_back_compat;
9c465d2c 605
f22644d7 606 $self->use_namespaces(1) unless defined $self->use_namespaces;
492dce8d 607 $self->generate_pod(1) unless defined $self->generate_pod;
43b982ea 608 $self->pod_comment_mode('auto') unless defined $self->pod_comment_mode;
609 $self->pod_comment_spillover_length(60) unless defined $self->pod_comment_spillover_length;
f22644d7 610
7824616e 611 $self;
612}
af31090c 613
7824616e 614sub _check_back_compat {
615 my ($self) = @_;
e8ad6491 616
a8d229ff 617# dynamic schemas will always be in 0.04006 mode, unless overridden
106a976a 618 if ($self->dynamic) {
fb3bb595 619# just in case, though no one is likely to dump a dynamic schema
1c95b304 620 $self->schema_version_to_dump('0.04006');
a8d229ff 621
66afce69 622 if (not %{ $self->naming }) {
623 warn <<EOF unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
624
625Dynamic schema detected, will run in 0.04006 mode.
626
627Set the 'naming' attribute or the SCHEMA_LOADER_BACKCOMPAT environment variable
628to disable this warning.
a0e0a56a 629
805dbe0a 630Also consider setting 'use_namespaces => 1' if/when upgrading.
631
a0e0a56a 632See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 for more
633details.
66afce69 634EOF
635 }
f53dcdf0 636 else {
637 $self->_upgrading_from('v4');
638 }
66afce69 639
a8d229ff 640 $self->naming->{relationships} ||= 'v4';
641 $self->naming->{monikers} ||= 'v4';
642
805dbe0a 643 if ($self->use_namespaces) {
644 $self->_upgrading_from_load_classes(1);
645 }
646 else {
647 $self->use_namespaces(0);
648 }
f22644d7 649
01012543 650 return;
651 }
652
653# otherwise check if we need backcompat mode for a static schema
7824616e 654 my $filename = $self->_get_dump_filename($self->schema_class);
655 return unless -e $filename;
656
657 open(my $fh, '<', $filename)
658 or croak "Cannot open '$filename' for reading: $!";
659
540a8149 660 my $load_classes = 0;
661 my $result_namespace = '';
f22644d7 662
7824616e 663 while (<$fh>) {
f22644d7 664 if (/^__PACKAGE__->load_classes;/) {
665 $load_classes = 1;
540a8149 666 } elsif (/result_namespace => '([^']+)'/) {
667 $result_namespace = $1;
805dbe0a 668 } elsif (my ($real_ver) =
669 /^# Created by DBIx::Class::Schema::Loader v(\d+\.\d+)/) {
670
671 if ($load_classes && (not defined $self->use_namespaces)) {
672 warn <<"EOF" unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
673
a1a91c42 674'load_classes;' static schema detected, turning off 'use_namespaces'.
805dbe0a 675
676Set the 'use_namespaces' attribute or the SCHEMA_LOADER_BACKCOMPAT environment
677variable to disable this warning.
678
679See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 for more
680details.
681EOF
682 $self->use_namespaces(0);
683 }
684 elsif ($load_classes && $self->use_namespaces) {
805dbe0a 685 $self->_upgrading_from_load_classes(1);
686 }
540a8149 687 elsif ((not $load_classes) && defined $self->use_namespaces
688 && (not $self->use_namespaces)) {
a4b94090 689 $self->_downgrading_to_load_classes(
690 $result_namespace || 'Result'
691 );
692 }
540a8149 693 elsif ((not defined $self->use_namespaces)
694 || $self->use_namespaces) {
695 if (not $self->result_namespace) {
696 $self->result_namespace($result_namespace || 'Result');
697 }
698 elsif ($result_namespace ne $self->result_namespace) {
699 $self->_rewriting_result_namespace(
700 $result_namespace || 'Result'
701 );
702 }
703 }
a8d229ff 704
a8d229ff 705 # XXX when we go past .0 this will need fixing
706 my ($v) = $real_ver =~ /([1-9])/;
707 $v = "v$v";
708
c5df7397 709 last if $v eq $CURRENT_V || $real_ver =~ /^0\.\d\d999/;
a0e0a56a 710
711 if (not %{ $self->naming }) {
712 warn <<"EOF" unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
713
714Version $real_ver static schema detected, turning on backcompat mode.
715
716Set the 'naming' attribute or the SCHEMA_LOADER_BACKCOMPAT environment variable
717to disable this warning.
718
9990e58f 719See: 'naming' in perldoc DBIx::Class::Schema::Loader::Base .
720
2a8e93e9 721See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 if upgrading
722from version 0.04006.
a0e0a56a 723EOF
724 }
f53dcdf0 725 else {
726 $self->_upgrading_from($v);
68d49e50 727 last;
f53dcdf0 728 }
a0e0a56a 729
f3a657ef 730 $self->naming->{relationships} ||= $v;
731 $self->naming->{monikers} ||= $v;
732 $self->naming->{column_accessors} ||= $v;
a8d229ff 733
a0e0a56a 734 $self->schema_version_to_dump($real_ver);
735
7824616e 736 last;
737 }
738 }
739 close $fh;
996be9ee 740}
741
8048320c 742sub _validate_class_args {
743 my $self = shift;
744 my $args = shift;
745
c5df7397 746 foreach my $k (@CLASS_ARGS) {
8048320c 747 next unless $self->$k;
748
749 my @classes = ref $self->$k eq 'ARRAY' ? @{ $self->$k } : $self->$k;
750 foreach my $c (@classes) {
751 # components default to being under the DBIx::Class namespace unless they
752 # are preceeded with a '+'
753 if ( $k =~ m/components$/ && $c !~ s/^\+// ) {
754 $c = 'DBIx::Class::' . $c;
755 }
756
757 # 1 == installed, 0 == not installed, undef == invalid classname
758 my $installed = Class::Inspector->installed($c);
759 if ( defined($installed) ) {
760 if ( $installed == 0 ) {
761 croak qq/$c, as specified in the loader option "$k", is not installed/;
762 }
763 } else {
764 croak qq/$c, as specified in the loader option "$k", is an invalid class name/;
765 }
766 }
767 }
768}
769
419a2eeb 770sub _find_file_in_inc {
771 my ($self, $file) = @_;
772
773 foreach my $prefix (@INC) {
af31090c 774 my $fullpath = File::Spec->catfile($prefix, $file);
775 return $fullpath if -f $fullpath
281d0f3e 776 # abs_path throws on Windows for nonexistant files
777 and eval { Cwd::abs_path($fullpath) } ne
778 (eval { Cwd::abs_path(File::Spec->catfile($self->dump_directory, $file)) } || '');
419a2eeb 779 }
780
781 return;
782}
783
fb3bb595 784sub _class_path {
f96ef30f 785 my ($self, $class) = @_;
786
787 my $class_path = $class;
788 $class_path =~ s{::}{/}g;
789 $class_path .= '.pm';
790
fb3bb595 791 return $class_path;
792}
793
794sub _find_class_in_inc {
795 my ($self, $class) = @_;
796
797 return $self->_find_file_in_inc($self->_class_path($class));
798}
799
a4b94090 800sub _rewriting {
801 my $self = shift;
802
803 return $self->_upgrading_from
804 || $self->_upgrading_from_load_classes
540a8149 805 || $self->_downgrading_to_load_classes
806 || $self->_rewriting_result_namespace
807 ;
a4b94090 808}
809
b24cb177 810sub _rewrite_old_classnames {
811 my ($self, $code) = @_;
812
a4b94090 813 return $code unless $self->_rewriting;
b24cb177 814
815 my %old_classes = reverse %{ $self->_upgrading_classes };
816
817 my $re = join '|', keys %old_classes;
818 $re = qr/\b($re)\b/;
819
68d49e50 820 $code =~ s/$re/$old_classes{$1} || $1/eg;
b24cb177 821
822 return $code;
823}
824
fb3bb595 825sub _load_external {
826 my ($self, $class) = @_;
827
0ca61324 828 return if $self->{skip_load_external};
829
ffc705f3 830 # so that we don't load our own classes, under any circumstances
831 local *INC = [ grep $_ ne $self->dump_directory, @INC ];
832
fb3bb595 833 my $real_inc_path = $self->_find_class_in_inc($class);
f96ef30f 834
ffc705f3 835 my $old_class = $self->_upgrading_classes->{$class}
a4b94090 836 if $self->_rewriting;
ffc705f3 837
838 my $old_real_inc_path = $self->_find_class_in_inc($old_class)
839 if $old_class && $old_class ne $class;
840
841 return unless $real_inc_path || $old_real_inc_path;
842
843 if ($real_inc_path) {
844 # If we make it to here, we loaded an external definition
845 warn qq/# Loaded external class definition for '$class'\n/
846 if $self->debug;
847
848 open(my $fh, '<', $real_inc_path)
849 or croak "Failed to open '$real_inc_path' for reading: $!";
b24cb177 850 my $code = do { local $/; <$fh> };
ffc705f3 851 close($fh)
852 or croak "Failed to close $real_inc_path: $!";
b24cb177 853 $code = $self->_rewrite_old_classnames($code);
ffc705f3 854
855 if ($self->dynamic) { # load the class too
856 # kill redefined warnings
502b65d4 857 my $warn_handler = $SIG{__WARN__} || sub { warn @_ };
ffc705f3 858 local $SIG{__WARN__} = sub {
502b65d4 859 $warn_handler->(@_)
860 unless $_[0] =~ /^Subroutine \S+ redefined/;
ffc705f3 861 };
b24cb177 862 eval $code;
ffc705f3 863 die $@ if $@;
864 }
b24cb177 865
866 $self->_ext_stmt($class,
867 qq|# These lines were loaded from '$real_inc_path' found in \@INC.\n|
868 .qq|# They are now part of the custom portion of this file\n|
869 .qq|# for you to hand-edit. If you do not either delete\n|
870 .qq|# this section or remove that file from \@INC, this section\n|
871 .qq|# will be repeated redundantly when you re-create this\n|
e770e9ce 872 .qq|# file again via Loader! See skip_load_external to disable\n|
873 .qq|# this feature.\n|
b24cb177 874 );
875 chomp $code;
876 $self->_ext_stmt($class, $code);
877 $self->_ext_stmt($class,
878 qq|# End of lines loaded from '$real_inc_path' |
879 );
996be9ee 880 }
106a976a 881
ffc705f3 882 if ($old_real_inc_path) {
b511f36e 883 my $code = slurp $old_real_inc_path;
884
ffc705f3 885 $self->_ext_stmt($class, <<"EOF");
886
30a4c064 887# These lines were loaded from '$old_real_inc_path',
b08ea624 888# based on the Result class name that would have been created by an older
30a4c064 889# version of the Loader. For a static schema, this happens only once during
e770e9ce 890# upgrade. See skip_load_external to disable this feature.
ffc705f3 891EOF
b24cb177 892
b24cb177 893 $code = $self->_rewrite_old_classnames($code);
894
ffc705f3 895 if ($self->dynamic) {
896 warn <<"EOF";
897
898Detected external content in '$old_real_inc_path', a class name that would have
b08ea624 899been used by an older version of the Loader.
ffc705f3 900
901* PLEASE RENAME THIS CLASS: from '$old_class' to '$class', as that is the
902new name of the Result.
903EOF
904 # kill redefined warnings
502b65d4 905 my $warn_handler = $SIG{__WARN__} || sub { warn @_ };
ffc705f3 906 local $SIG{__WARN__} = sub {
502b65d4 907 $warn_handler->(@_)
908 unless $_[0] =~ /^Subroutine \S+ redefined/;
ffc705f3 909 };
ffc705f3 910 eval $code;
911 die $@ if $@;
912 }
913
b24cb177 914 chomp $code;
915 $self->_ext_stmt($class, $code);
ffc705f3 916 $self->_ext_stmt($class,
917 qq|# End of lines loaded from '$old_real_inc_path' |
918 );
9e8033c1 919 }
996be9ee 920}
921
922=head2 load
923
924Does the actual schema-construction work.
925
926=cut
927
928sub load {
929 my $self = shift;
930
bfb43060 931 $self->_load_tables(
932 $self->_tables_list({ constraint => $self->constraint, exclude => $self->exclude })
933 );
b97c2c1e 934}
935
936=head2 rescan
937
a60b5b8d 938Arguments: schema
939
b511f36e 940Rescan the database for changes. Returns a list of the newly added table
941monikers.
a60b5b8d 942
b511f36e 943The schema argument should be the schema class or object to be affected. It
944should probably be derived from the original schema_class used during L</load>.
b97c2c1e 945
946=cut
947
948sub rescan {
a60b5b8d 949 my ($self, $schema) = @_;
950
951 $self->{schema} = $schema;
7824616e 952 $self->_relbuilder->{schema} = $schema;
b97c2c1e 953
954 my @created;
bfb43060 955 my @current = $self->_tables_list({ constraint => $self->constraint, exclude => $self->exclude });
0c1d5b47 956
bfb43060 957 foreach my $table (@current) {
b97c2c1e 958 if(!exists $self->{_tables}->{$table}) {
959 push(@created, $table);
960 }
961 }
962
0c1d5b47 963 my %current;
964 @current{@current} = ();
965 foreach my $table (keys %{ $self->{_tables} }) {
966 if (not exists $current{$table}) {
967 $self->_unregister_source_for_table($table);
968 }
969 }
970
b511f36e 971 delete $self->{_dump_storage};
972 delete $self->{_relations_started};
973
974 my $loaded = $self->_load_tables(@current);
a60b5b8d 975
b511f36e 976 return map { $self->monikers->{$_} } @created;
b97c2c1e 977}
978
7824616e 979sub _relbuilder {
66afce69 980 no warnings 'uninitialized';
7824616e 981 my ($self) = @_;
3fed44ca 982
983 return if $self->{skip_relationships};
984
a8d229ff 985 if ($self->naming->{relationships} eq 'v4') {
986 require DBIx::Class::Schema::Loader::RelBuilder::Compat::v0_040;
987 return $self->{relbuilder} ||=
988 DBIx::Class::Schema::Loader::RelBuilder::Compat::v0_040->new(
19b7d71c 989 $self->schema,
990 $self->inflect_plural,
991 $self->inflect_singular,
992 $self->relationship_attrs,
a8d229ff 993 );
994 }
ecf930e6 995 elsif ($self->naming->{relationships} eq 'v5') {
996 require DBIx::Class::Schema::Loader::RelBuilder::Compat::v0_05;
997 return $self->{relbuilder} ||= DBIx::Class::Schema::Loader::RelBuilder::Compat::v0_05->new (
998 $self->schema,
999 $self->inflect_plural,
1000 $self->inflect_singular,
1001 $self->relationship_attrs,
1002 );
1003 }
19b7d71c 1004 elsif ($self->naming->{relationships} eq 'v6') {
1005 require DBIx::Class::Schema::Loader::RelBuilder::Compat::v0_06;
1006 return $self->{relbuilder} ||= DBIx::Class::Schema::Loader::RelBuilder::Compat::v0_06->new (
1007 $self->schema,
1008 $self->inflect_plural,
1009 $self->inflect_singular,
1010 $self->relationship_attrs,
1011 );
1012 }
a8d229ff 1013
ecf930e6 1014 return $self->{relbuilder} ||= DBIx::Class::Schema::Loader::RelBuilder->new (
1015 $self->schema,
1016 $self->inflect_plural,
1017 $self->inflect_singular,
1018 $self->relationship_attrs,
7824616e 1019 );
1020}
1021
b97c2c1e 1022sub _load_tables {
1023 my ($self, @tables) = @_;
1024
b97c2c1e 1025 # Save the new tables to the tables list
a60b5b8d 1026 foreach (@tables) {
1027 $self->{_tables}->{$_} = 1;
1028 }
f96ef30f 1029
af31090c 1030 $self->_make_src_class($_) for @tables;
27305cc1 1031
27305cc1 1032 # sanity-check for moniker clashes
1033 my $inverse_moniker_idx;
1034 for (keys %{$self->monikers}) {
1035 push @{$inverse_moniker_idx->{$self->monikers->{$_}}}, $_;
1036 }
1037
1038 my @clashes;
1039 for (keys %$inverse_moniker_idx) {
1040 my $tables = $inverse_moniker_idx->{$_};
1041 if (@$tables > 1) {
1042 push @clashes, sprintf ("tables %s reduced to the same source moniker '%s'",
1043 join (', ', map { "'$_'" } @$tables),
1044 $_,
1045 );
1046 }
1047 }
1048
1049 if (@clashes) {
1050 die 'Unable to load schema - chosen moniker/class naming style results in moniker clashes. '
1051 . 'Either change the naming style, or supply an explicit moniker_map: '
1052 . join ('; ', @clashes)
1053 . "\n"
1054 ;
1055 }
1056
1057
f96ef30f 1058 $self->_setup_src_meta($_) for @tables;
1059
e8ad6491 1060 if(!$self->skip_relationships) {
181cc907 1061 # The relationship loader needs a working schema
af31090c 1062 $self->{quiet} = 1;
79193756 1063 local $self->{dump_directory} = $self->{temp_directory};
106a976a 1064 $self->_reload_classes(\@tables);
e8ad6491 1065 $self->_load_relationships($_) for @tables;
af31090c 1066 $self->{quiet} = 0;
79193756 1067
1068 # Remove that temp dir from INC so it doesn't get reloaded
ffc705f3 1069 @INC = grep $_ ne $self->dump_directory, @INC;
e8ad6491 1070 }
1071
f96ef30f 1072 $self->_load_external($_)
75451704 1073 for map { $self->classes->{$_} } @tables;
f96ef30f 1074
106a976a 1075 # Reload without unloading first to preserve any symbols from external
1076 # packages.
1077 $self->_reload_classes(\@tables, 0);
996be9ee 1078
5223f24a 1079 # Drop temporary cache
1080 delete $self->{_cache};
1081
c39e3507 1082 return \@tables;
996be9ee 1083}
1084
af31090c 1085sub _reload_classes {
106a976a 1086 my ($self, $tables, $unload) = @_;
1087
1088 my @tables = @$tables;
1089 $unload = 1 unless defined $unload;
181cc907 1090
4daef04f 1091 # so that we don't repeat custom sections
1092 @INC = grep $_ ne $self->dump_directory, @INC;
1093
181cc907 1094 $self->_dump_to_dir(map { $self->classes->{$_} } @tables);
e9b8719e 1095
1096 unshift @INC, $self->dump_directory;
af31090c 1097
706ef173 1098 my @to_register;
1099 my %have_source = map { $_ => $self->schema->source($_) }
1100 $self->schema->sources;
1101
181cc907 1102 for my $table (@tables) {
1103 my $moniker = $self->monikers->{$table};
1104 my $class = $self->classes->{$table};
0ae6b65d 1105
1106 {
1107 no warnings 'redefine';
1108 local *Class::C3::reinitialize = sub {};
1109 use warnings;
1110
c9cf9b4d 1111 if ($class->can('meta')) {
1112 $class->meta->make_mutable;
1113 }
106a976a 1114 Class::Unload->unload($class) if $unload;
706ef173 1115 my ($source, $resultset_class);
1116 if (
1117 ($source = $have_source{$moniker})
1118 && ($resultset_class = $source->resultset_class)
1119 && ($resultset_class ne 'DBIx::Class::ResultSet')
1120 ) {
1121 my $has_file = Class::Inspector->loaded_filename($resultset_class);
c9cf9b4d 1122 if ($resultset_class->can('meta')) {
1123 $resultset_class->meta->make_mutable;
1124 }
106a976a 1125 Class::Unload->unload($resultset_class) if $unload;
1126 $self->_reload_class($resultset_class) if $has_file;
0ae6b65d 1127 }
106a976a 1128 $self->_reload_class($class);
af31090c 1129 }
706ef173 1130 push @to_register, [$moniker, $class];
1131 }
af31090c 1132
706ef173 1133 Class::C3->reinitialize;
1134 for (@to_register) {
1135 $self->schema->register_class(@$_);
af31090c 1136 }
1137}
1138
106a976a 1139# We use this instead of ensure_class_loaded when there are package symbols we
1140# want to preserve.
1141sub _reload_class {
1142 my ($self, $class) = @_;
1143
1144 my $class_path = $self->_class_path($class);
1145 delete $INC{ $class_path };
f53dcdf0 1146
1147# kill redefined warnings
502b65d4 1148 my $warn_handler = $SIG{__WARN__} || sub { warn @_ };
f53dcdf0 1149 local $SIG{__WARN__} = sub {
502b65d4 1150 $warn_handler->(@_)
1151 unless $_[0] =~ /^Subroutine \S+ redefined/;
f53dcdf0 1152 };
106a976a 1153 eval "require $class;";
c9cf9b4d 1154 die "Failed to reload class $class: $@" if $@;
106a976a 1155}
1156
996be9ee 1157sub _get_dump_filename {
1158 my ($self, $class) = (@_);
1159
1160 $class =~ s{::}{/}g;
1161 return $self->dump_directory . q{/} . $class . q{.pm};
1162}
1163
1164sub _ensure_dump_subdirs {
1165 my ($self, $class) = (@_);
1166
1167 my @name_parts = split(/::/, $class);
dd03ee1a 1168 pop @name_parts; # we don't care about the very last element,
1169 # which is a filename
1170
996be9ee 1171 my $dir = $self->dump_directory;
7cab3ab7 1172 while (1) {
1173 if(!-d $dir) {
25328cc4 1174 mkdir($dir) or croak "mkdir('$dir') failed: $!";
996be9ee 1175 }
7cab3ab7 1176 last if !@name_parts;
1177 $dir = File::Spec->catdir($dir, shift @name_parts);
996be9ee 1178 }
1179}
1180
1181sub _dump_to_dir {
af31090c 1182 my ($self, @classes) = @_;
996be9ee 1183
fc2b71fd 1184 my $schema_class = $self->schema_class;
9c9c2f2b 1185 my $schema_base_class = $self->schema_base_class || 'DBIx::Class::Schema';
996be9ee 1186
e9b8719e 1187 my $target_dir = $self->dump_directory;
af31090c 1188 warn "Dumping manual schema for $schema_class to directory $target_dir ...\n"
1189 unless $self->{dynamic} or $self->{quiet};
996be9ee 1190
7cab3ab7 1191 my $schema_text =
1192 qq|package $schema_class;\n\n|
b4dcbcc5 1193 . qq|# Created by DBIx::Class::Schema::Loader\n|
1194 . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|
dcaf302a 1195 . qq|use strict;\nuse warnings;\n\n|;
1196 if ($self->use_moose) {
c9cf9b4d 1197 $schema_text.= qq|use Moose;\nuse MooseX::NonMoose;\nuse namespace::autoclean;\nextends '$schema_base_class';\n\n|;
dcaf302a 1198 }
1199 else {
1200 $schema_text .= qq|use base '$schema_base_class';\n\n|;
1201 }
f44ecc2f 1202
f44ecc2f 1203 if ($self->use_namespaces) {
1204 $schema_text .= qq|__PACKAGE__->load_namespaces|;
1205 my $namespace_options;
2a8e93e9 1206
1207 my @attr = qw/resultset_namespace default_resultset_class/;
1208
1209 unshift @attr, 'result_namespace' unless (not $self->result_namespace) || $self->result_namespace eq 'Result';
1210
1211 for my $attr (@attr) {
f44ecc2f 1212 if ($self->$attr) {
1213 $namespace_options .= qq| $attr => '| . $self->$attr . qq|',\n|
1214 }
1215 }
1216 $schema_text .= qq|(\n$namespace_options)| if $namespace_options;
1217 $schema_text .= qq|;\n|;
1218 }
1219 else {
1220 $schema_text .= qq|__PACKAGE__->load_classes;\n|;
f44ecc2f 1221 }
996be9ee 1222
1c95b304 1223 {
1224 local $self->{version_to_dump} = $self->schema_version_to_dump;
68d49e50 1225 $self->_write_classfile($schema_class, $schema_text, 1);
1c95b304 1226 }
996be9ee 1227
2229729e 1228 my $result_base_class = $self->result_base_class || 'DBIx::Class::Core';
9c9c2f2b 1229
af31090c 1230 foreach my $src_class (@classes) {
7cab3ab7 1231 my $src_text =
1232 qq|package $src_class;\n\n|
b4dcbcc5 1233 . qq|# Created by DBIx::Class::Schema::Loader\n|
1234 . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|
dcaf302a 1235 . qq|use strict;\nuse warnings;\n\n|;
1236 if ($self->use_moose) {
c9cf9b4d 1237 $src_text.= qq|use Moose;\nuse MooseX::NonMoose;\nuse namespace::autoclean;\nextends '$result_base_class';\n\n|;
dcaf302a 1238 }
1239 else {
1240 $src_text .= qq|use base '$result_base_class';\n\n|;
1241 }
7cab3ab7 1242 $self->_write_classfile($src_class, $src_text);
02356864 1243 }
996be9ee 1244
a4b94090 1245 # remove Result dir if downgrading from use_namespaces, and there are no
1246 # files left.
b5f1b43c 1247 if (my $result_ns = $self->_downgrading_to_load_classes
1248 || $self->_rewriting_result_namespace) {
540a8149 1249 my $result_namespace = $self->_result_namespace(
1250 $schema_class,
1251 $result_ns,
1252 );
a4b94090 1253
540a8149 1254 (my $result_dir = $result_namespace) =~ s{::}{/}g;
a4b94090 1255 $result_dir = $self->dump_directory . '/' . $result_dir;
1256
1257 unless (my @files = glob "$result_dir/*") {
1258 rmdir $result_dir;
1259 }
1260 }
1261
af31090c 1262 warn "Schema dump completed.\n" unless $self->{dynamic} or $self->{quiet};
1263
7cab3ab7 1264}
1265
79193756 1266sub _sig_comment {
1267 my ($self, $version, $ts) = @_;
1268 return qq|\n\n# Created by DBIx::Class::Schema::Loader|
1269 . qq| v| . $version
1270 . q| @ | . $ts
1271 . qq|\n# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:|;
1272}
1273
7cab3ab7 1274sub _write_classfile {
68d49e50 1275 my ($self, $class, $text, $is_schema) = @_;
7cab3ab7 1276
1277 my $filename = $self->_get_dump_filename($class);
1278 $self->_ensure_dump_subdirs($class);
1279
28b4691d 1280 if (-f $filename && $self->really_erase_my_files) {
7cab3ab7 1281 warn "Deleting existing file '$filename' due to "
af31090c 1282 . "'really_erase_my_files' setting\n" unless $self->{quiet};
7cab3ab7 1283 unlink($filename);
1284 }
1285
79193756 1286 my ($custom_content, $old_md5, $old_ver, $old_ts) = $self->_get_custom_content($class, $filename);
17ca645f 1287
c9cf9b4d 1288 # If upgrading to use_moose=1 replace default custom content with default Moose custom content.
1289 # If there is already custom content, which does not have the Moose content, add it.
1290 if ($self->use_moose) {
1291 local $self->{use_moose} = 0;
1292
1293 if ($custom_content eq $self->_default_custom_content) {
1294 local $self->{use_moose} = 1;
1295
1296 $custom_content = $self->_default_custom_content;
1297 }
1298 else {
1299 local $self->{use_moose} = 1;
1300
1301 if ($custom_content !~ /\Q@{[$self->_default_moose_custom_content]}\E/) {
1302 $custom_content .= $self->_default_custom_content;
1303 }
1304 }
1305 }
1306
e1373c52 1307 if (my $old_class = $self->_upgrading_classes->{$class}) {
1308 my $old_filename = $self->_get_dump_filename($old_class);
f53dcdf0 1309
e1373c52 1310 my ($old_custom_content) = $self->_get_custom_content(
1311 $old_class, $old_filename, 0 # do not add default comment
1312 );
ffc705f3 1313
e1373c52 1314 $old_custom_content =~ s/\n\n# You can replace.*\n1;\n//;
f53dcdf0 1315
e1373c52 1316 if ($old_custom_content) {
1317 $custom_content =
1318 "\n" . $old_custom_content . "\n" . $custom_content;
f53dcdf0 1319 }
e1373c52 1320
1321 unlink $old_filename;
f53dcdf0 1322 }
1323
b24cb177 1324 $custom_content = $self->_rewrite_old_classnames($custom_content);
1325
7cab3ab7 1326 $text .= qq|$_\n|
1327 for @{$self->{_dump_storage}->{$class} || []};
1328
79193756 1329 # Check and see if the dump is infact differnt
1330
1331 my $compare_to;
1332 if ($old_md5) {
1333 $compare_to = $text . $self->_sig_comment($old_ver, $old_ts);
1334
1335
1336 if (Digest::MD5::md5_base64($compare_to) eq $old_md5) {
68d49e50 1337 return unless $self->_upgrading_from && $is_schema;
79193756 1338 }
1339 }
1340
1341 $text .= $self->_sig_comment(
01012543 1342 $self->version_to_dump,
79193756 1343 POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime)
1344 );
7cab3ab7 1345
1346 open(my $fh, '>', $filename)
1347 or croak "Cannot open '$filename' for writing: $!";
1348
1349 # Write the top half and its MD5 sum
a4476f41 1350 print $fh $text . Digest::MD5::md5_base64($text) . "\n";
7cab3ab7 1351
1352 # Write out anything loaded via external partial class file in @INC
1353 print $fh qq|$_\n|
1354 for @{$self->{_ext_storage}->{$class} || []};
1355
1eea4fb1 1356 # Write out any custom content the user has added
7cab3ab7 1357 print $fh $custom_content;
1358
1359 close($fh)
e9b8719e 1360 or croak "Error closing '$filename': $!";
7cab3ab7 1361}
1362
c9cf9b4d 1363sub _default_moose_custom_content {
1364 return qq|\n__PACKAGE__->meta->make_immutable;|;
1365}
1366
79193756 1367sub _default_custom_content {
dcaf302a 1368 my $self = shift;
1369 my $default = qq|\n\n# You can replace this text with custom|
1370 . qq| content, and it will be preserved on regeneration|;
1371 if ($self->use_moose) {
c9cf9b4d 1372 $default .= $self->_default_moose_custom_content;
dcaf302a 1373 }
1374 $default .= qq|\n1;\n|;
1375 return $default;
79193756 1376}
1377
7cab3ab7 1378sub _get_custom_content {
ffc705f3 1379 my ($self, $class, $filename, $add_default) = @_;
1380
1381 $add_default = 1 unless defined $add_default;
7cab3ab7 1382
79193756 1383 return ($self->_default_custom_content) if ! -f $filename;
1384
7cab3ab7 1385 open(my $fh, '<', $filename)
1386 or croak "Cannot open '$filename' for reading: $!";
1387
1388 my $mark_re =
419a2eeb 1389 qr{^(# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:)([A-Za-z0-9/+]{22})\n};
7cab3ab7 1390
7cab3ab7 1391 my $buffer = '';
79193756 1392 my ($md5, $ts, $ver);
7cab3ab7 1393 while(<$fh>) {
79193756 1394 if(!$md5 && /$mark_re/) {
1395 $md5 = $2;
1396 my $line = $1;
1397
1398 # Pull out the previous version and timestamp
1399 ($ver, $ts) = $buffer =~ m/# Created by DBIx::Class::Schema::Loader v(.*?) @ (.*?)$/s;
1400
1401 $buffer .= $line;
b4cc5793 1402 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 1403 if !$self->overwrite_modifications && Digest::MD5::md5_base64($buffer) ne $md5;
7cab3ab7 1404
1405 $buffer = '';
1406 }
1407 else {
1408 $buffer .= $_;
1409 }
996be9ee 1410 }
1411
28b4691d 1412 croak "Cannot not overwrite '$filename' without 'really_erase_my_files',"
419a2eeb 1413 . " it does not appear to have been generated by Loader"
79193756 1414 if !$md5;
5ef3c771 1415
79193756 1416 # Default custom content:
ffc705f3 1417 $buffer ||= $self->_default_custom_content if $add_default;
5ef3c771 1418
79193756 1419 return ($buffer, $md5, $ver, $ts);
996be9ee 1420}
1421
1422sub _use {
1423 my $self = shift;
1424 my $target = shift;
1425
1426 foreach (@_) {
cb54990b 1427 warn "$target: use $_;" if $self->debug;
996be9ee 1428 $self->_raw_stmt($target, "use $_;");
996be9ee 1429 }
1430}
1431
1432sub _inject {
1433 my $self = shift;
1434 my $target = shift;
1435 my $schema_class = $self->schema_class;
1436
af31090c 1437 my $blist = join(q{ }, @_);
1438 warn "$target: use base qw/ $blist /;" if $self->debug && @_;
1439 $self->_raw_stmt($target, "use base qw/ $blist /;") if @_;
996be9ee 1440}
1441
540a8149 1442sub _result_namespace {
1443 my ($self, $schema_class, $ns) = @_;
1444 my @result_namespace;
1445
1446 if ($ns =~ /^\+(.*)/) {
1447 # Fully qualified namespace
1448 @result_namespace = ($1)
1449 }
1450 else {
1451 # Relative namespace
1452 @result_namespace = ($schema_class, $ns);
1453 }
1454
1455 return wantarray ? @result_namespace : join '::', @result_namespace;
1456}
1457
f96ef30f 1458# Create class with applicable bases, setup monikers, etc
1459sub _make_src_class {
1460 my ($self, $table) = @_;
996be9ee 1461
a13b2803 1462 my $schema = $self->schema;
1463 my $schema_class = $self->schema_class;
996be9ee 1464
f96ef30f 1465 my $table_moniker = $self->_table2moniker($table);
f44ecc2f 1466 my @result_namespace = ($schema_class);
1467 if ($self->use_namespaces) {
1468 my $result_namespace = $self->result_namespace || 'Result';
540a8149 1469 @result_namespace = $self->_result_namespace(
1470 $schema_class,
1471 $result_namespace,
1472 );
f44ecc2f 1473 }
1474 my $table_class = join(q{::}, @result_namespace, $table_moniker);
996be9ee 1475
805dbe0a 1476 if ((my $upgrading_v = $self->_upgrading_from)
a4b94090 1477 || $self->_rewriting) {
805dbe0a 1478 local $self->naming->{monikers} = $upgrading_v
1479 if $upgrading_v;
1480
1481 my @result_namespace = @result_namespace;
a4b94090 1482 if ($self->_upgrading_from_load_classes) {
1483 @result_namespace = ($schema_class);
1484 }
1485 elsif (my $ns = $self->_downgrading_to_load_classes) {
540a8149 1486 @result_namespace = $self->_result_namespace(
1487 $schema_class,
1488 $ns,
1489 );
1490 }
1491 elsif ($ns = $self->_rewriting_result_namespace) {
1492 @result_namespace = $self->_result_namespace(
1493 $schema_class,
1494 $ns,
1495 );
a4b94090 1496 }
f53dcdf0 1497
1498 my $old_class = join(q{::}, @result_namespace,
1499 $self->_table2moniker($table));
1500
68d49e50 1501 $self->_upgrading_classes->{$table_class} = $old_class
1502 unless $table_class eq $old_class;
f53dcdf0 1503 }
1504
bfb43060 1505# this was a bad idea, should be ok now without it
1506# my $table_normalized = lc $table;
1507# $self->classes->{$table_normalized} = $table_class;
1508# $self->monikers->{$table_normalized} = $table_moniker;
1509
f96ef30f 1510 $self->classes->{$table} = $table_class;
f96ef30f 1511 $self->monikers->{$table} = $table_moniker;
996be9ee 1512
f96ef30f 1513 $self->_use ($table_class, @{$self->additional_classes});
af31090c 1514 $self->_inject($table_class, @{$self->left_base_classes});
996be9ee 1515
2229729e 1516 if (my @components = @{ $self->components }) {
1517 $self->_dbic_stmt($table_class, 'load_components', @components);
1518 }
996be9ee 1519
f96ef30f 1520 $self->_dbic_stmt($table_class, 'load_resultset_components', @{$self->resultset_components})
1521 if @{$self->resultset_components};
af31090c 1522 $self->_inject($table_class, @{$self->additional_base_classes});
f96ef30f 1523}
996be9ee 1524
9fdf3d5b 1525sub _resolve_col_accessor_collisions {
1526 my ($self, $col_info) = @_;
1527
1528 my $base = $self->result_base_class || 'DBIx::Class::Core';
410e3f58 1529 my @components = map "DBIx::Class::$_", @{ $self->components || [] };
9fdf3d5b 1530
1531 my @methods;
1532
1533 for my $class ($base, @components) {
1534 eval "require ${class};";
1535 die $@ if $@;
1536
1537 push @methods, @{ Class::Inspector->methods($class) || [] };
1538 }
1539
1540 my %methods;
1541 @methods{@methods} = ();
1542
1543 while (my ($col, $info) = each %$col_info) {
1544 my $accessor = $info->{accessor} || $col;
1545
c9486c78 1546 next if $accessor eq 'id'; # special case (very common column)
9fdf3d5b 1547
1548 if (exists $methods{$accessor}) {
1e473081 1549 $info->{accessor} = undef;
9fdf3d5b 1550 }
1551 }
1552}
1553
f3a657ef 1554sub _make_column_accessor_name {
1555 my ($self, $column_name) = @_;
1556
cc4f11a2 1557 return join '_', map lc, split_name $column_name;
f3a657ef 1558}
1559
af31090c 1560# Set up metadata (cols, pks, etc)
f96ef30f 1561sub _setup_src_meta {
1562 my ($self, $table) = @_;
996be9ee 1563
f96ef30f 1564 my $schema = $self->schema;
1565 my $schema_class = $self->schema_class;
a13b2803 1566
f96ef30f 1567 my $table_class = $self->classes->{$table};
1568 my $table_moniker = $self->monikers->{$table};
996be9ee 1569
ff30991a 1570 my $table_name = $table;
1571 my $name_sep = $self->schema->storage->sql_maker->name_sep;
1572
c177d483 1573 if ($name_sep && $table_name =~ /\Q$name_sep\E/) {
ff30991a 1574 $table_name = \ $self->_quote_table_name($table_name);
1575 }
1576
b1d11550 1577 my $full_table_name = ($self->qualify_objects ? ($self->db_schema . '.') : '') . (ref $table_name ? $$table_name : $table_name);
1578
1579 # be careful to not create refs Data::Dump can "optimize"
1580 $full_table_name = \do {"".$full_table_name} if ref $table_name;
1581
1582 $self->_dbic_stmt($table_class, 'table', $full_table_name);
996be9ee 1583
f96ef30f 1584 my $cols = $self->_table_columns($table);
45be2ce7 1585 my $col_info = $self->__columns_info_for($table);
df55c5fa 1586
1587 while (my ($col, $info) = each %$col_info) {
1588 if ($col =~ /\W/) {
1589 ($info->{accessor} = $col) =~ s/\W+/_/g;
1590 }
1591 }
1592
bc1cb85e 1593 if ($self->preserve_case) {
df55c5fa 1594 while (my ($col, $info) = each %$col_info) {
f3a657ef 1595 if ($col ne lc($col)) {
1596 if ((not exists $self->naming->{column_accessors}) || (($self->naming->{column_accessors} =~ /(\d+)/)[0] >= 7)) {
df55c5fa 1597 $info->{accessor} = $self->_make_column_accessor_name($info->{accessor} || $col);
f3a657ef 1598 }
1599 else {
df55c5fa 1600 $info->{accessor} = lc($info->{accessor} || $col);
f3a657ef 1601 }
1602 }
c9373b79 1603 }
c9486c78 1604 }
1605 else {
1606 # XXX this needs to go away
45be2ce7 1607 $col_info = { map { lc($_), $col_info->{$_} } keys %$col_info };
1608 }
c9373b79 1609
9fdf3d5b 1610 $self->_resolve_col_accessor_collisions($col_info);
1611
45be2ce7 1612 my $fks = $self->_table_fk_info($table);
565335e6 1613
10c0c4f3 1614 foreach my $fkdef (@$fks) {
45be2ce7 1615 for my $col (@{ $fkdef->{local_columns} }) {
1616 $col_info->{$col}{is_foreign_key} = 1;
e7213f4f 1617 }
996be9ee 1618 }
10c0c4f3 1619
1620 my $pks = $self->_table_pk_info($table) || [];
1621
1622 foreach my $pkcol (@$pks) {
1623 $col_info->{$pkcol}{is_nullable} = 0;
1624 }
1625
45be2ce7 1626 $self->_dbic_stmt(
1627 $table_class,
1628 'add_columns',
1629 map { $_, ($col_info->{$_}||{}) } @$cols
1630 );
996be9ee 1631
d70c335f 1632 my %uniq_tag; # used to eliminate duplicate uniqs
1633
f96ef30f 1634 @$pks ? $self->_dbic_stmt($table_class,'set_primary_key',@$pks)
1635 : carp("$table has no primary key");
d70c335f 1636 $uniq_tag{ join("\0", @$pks) }++ if @$pks; # pk is a uniq
996be9ee 1637
f96ef30f 1638 my $uniqs = $self->_table_uniq_info($table) || [];
d70c335f 1639 for (@$uniqs) {
1640 my ($name, $cols) = @$_;
1641 next if $uniq_tag{ join("\0", @$cols) }++; # skip duplicates
1642 $self->_dbic_stmt($table_class,'add_unique_constraint', $name, $cols);
1643 }
1644
996be9ee 1645}
1646
d67d058e 1647sub __columns_info_for {
1648 my ($self, $table) = @_;
1649
1650 my $result = $self->_columns_info_for($table);
1651
1652 while (my ($col, $info) = each %$result) {
1653 $info = { %$info, %{ $self->_custom_column_info ($table, $col, $info) } };
1654 $info = { %$info, %{ $self->_datetime_column_info($table, $col, $info) } };
1655
1656 $result->{$col} = $info;
1657 }
1658
1659 return $result;
1660}
1661
996be9ee 1662=head2 tables
1663
1664Returns a sorted list of loaded tables, using the original database table
1665names.
1666
1667=cut
1668
1669sub tables {
1670 my $self = shift;
1671
b97c2c1e 1672 return keys %{$self->_tables};
996be9ee 1673}
1674
1675# Make a moniker from a table
c39e403e 1676sub _default_table2moniker {
66afce69 1677 no warnings 'uninitialized';
c39e403e 1678 my ($self, $table) = @_;
1679
a8d229ff 1680 if ($self->naming->{monikers} eq 'v4') {
1681 return join '', map ucfirst, split /[\W_]+/, lc $table;
1682 }
ecf930e6 1683 elsif ($self->naming->{monikers} eq 'v5') {
1684 return join '', map ucfirst, split /[\W_]+/,
1685 Lingua::EN::Inflect::Number::to_S(lc $table);
1686 }
9990e58f 1687 elsif ($self->naming->{monikers} eq 'v6') {
1688 (my $as_phrase = lc $table) =~ s/_+/ /g;
1689 my $inflected = Lingua::EN::Inflect::Phrase::to_S($as_phrase);
1690
1691 return join '', map ucfirst, split /\W+/, $inflected;
1692 }
1693
cc4f11a2 1694 my @words = map lc, split_name $table;
9990e58f 1695 my $as_phrase = join ' ', @words;
ecf930e6 1696
ecf930e6 1697 my $inflected = Lingua::EN::Inflect::Phrase::to_S($as_phrase);
a8d229ff 1698
ecf930e6 1699 return join '', map ucfirst, split /\W+/, $inflected;
c39e403e 1700}
1701
996be9ee 1702sub _table2moniker {
1703 my ( $self, $table ) = @_;
1704
1705 my $moniker;
1706
1707 if( ref $self->moniker_map eq 'HASH' ) {
1708 $moniker = $self->moniker_map->{$table};
1709 }
1710 elsif( ref $self->moniker_map eq 'CODE' ) {
1711 $moniker = $self->moniker_map->($table);
1712 }
1713
c39e403e 1714 $moniker ||= $self->_default_table2moniker($table);
996be9ee 1715
1716 return $moniker;
1717}
1718
1719sub _load_relationships {
e8ad6491 1720 my ($self, $table) = @_;
996be9ee 1721
e8ad6491 1722 my $tbl_fk_info = $self->_table_fk_info($table);
1723 foreach my $fkdef (@$tbl_fk_info) {
1724 $fkdef->{remote_source} =
1725 $self->monikers->{delete $fkdef->{remote_table}};
996be9ee 1726 }
26f1c8c9 1727 my $tbl_uniq_info = $self->_table_uniq_info($table);
996be9ee 1728
e8ad6491 1729 my $local_moniker = $self->monikers->{$table};
7824616e 1730 my $rel_stmts = $self->_relbuilder->generate_code($local_moniker, $tbl_fk_info, $tbl_uniq_info);
996be9ee 1731
996be9ee 1732 foreach my $src_class (sort keys %$rel_stmts) {
1733 my $src_stmts = $rel_stmts->{$src_class};
1734 foreach my $stmt (@$src_stmts) {
1735 $self->_dbic_stmt($src_class,$stmt->{method},@{$stmt->{args}});
1736 }
1737 }
1738}
1739
1740# Overload these in driver class:
1741
1742# Returns an arrayref of column names
1743sub _table_columns { croak "ABSTRACT METHOD" }
1744
1745# Returns arrayref of pk col names
1746sub _table_pk_info { croak "ABSTRACT METHOD" }
1747
1748# Returns an arrayref of uniqs [ [ foo => [ col1, col2 ] ], [ bar => [ ... ] ] ]
1749sub _table_uniq_info { croak "ABSTRACT METHOD" }
1750
1751# Returns an arrayref of foreign key constraints, each
1752# being a hashref with 3 keys:
1753# local_columns (arrayref), remote_columns (arrayref), remote_table
1754sub _table_fk_info { croak "ABSTRACT METHOD" }
1755
1756# Returns an array of lower case table names
1757sub _tables_list { croak "ABSTRACT METHOD" }
1758
1759# Execute a constructive DBIC class method, with debug/dump_to_dir hooks.
1760sub _dbic_stmt {
bf654ab9 1761 my $self = shift;
1762 my $class = shift;
996be9ee 1763 my $method = shift;
bf654ab9 1764
1765 # generate the pod for this statement, storing it with $self->_pod
43b982ea 1766 $self->_make_pod( $class, $method, @_ ) if $self->generate_pod;
bf654ab9 1767
1768 my $args = dump(@_);
1769 $args = '(' . $args . ')' if @_ < 2;
1770 my $stmt = $method . $args . q{;};
1771
1772 warn qq|$class\->$stmt\n| if $self->debug;
1773 $self->_raw_stmt($class, '__PACKAGE__->' . $stmt);
1774 return;
1775}
1776
1777# generates the accompanying pod for a DBIC class method statement,
1778# storing it with $self->_pod
1779sub _make_pod {
1780 my $self = shift;
1781 my $class = shift;
1782 my $method = shift;
1783
fbcfebdd 1784 if ( $method eq 'table' ) {
1785 my ($table) = @_;
43b982ea 1786 my $pcm = $self->pod_comment_mode;
1787 my ($comment, $comment_overflows, $comment_in_name, $comment_in_desc);
fbcfebdd 1788 if ( $self->can('_table_comment') ) {
43b982ea 1789 $comment = $self->_table_comment($table);
1790 $comment_overflows = ($comment and length $comment > $self->pod_comment_spillover_length);
1791 $comment_in_name = ($pcm eq 'name' or ($pcm eq 'auto' and !$comment_overflows));
1792 $comment_in_desc = ($pcm eq 'description' or ($pcm eq 'auto' and $comment_overflows));
fbcfebdd 1793 }
43b982ea 1794 $self->_pod( $class, "=head1 NAME" );
1795 my $table_descr = $class;
1796 $table_descr .= " - " . $comment if $comment and $comment_in_name;
fbcfebdd 1797 $self->{_class2table}{ $class } = $table;
1798 $self->_pod( $class, $table_descr );
43b982ea 1799 if ($comment and $comment_in_desc) {
1800 $self->_pod( $class, "=head1 DESCRIPTION" );
1801 $self->_pod( $class, $comment );
1802 }
fbcfebdd 1803 $self->_pod_cut( $class );
1804 } elsif ( $method eq 'add_columns' ) {
1805 $self->_pod( $class, "=head1 ACCESSORS" );
79a00530 1806 my $col_counter = 0;
1807 my @cols = @_;
1808 while( my ($name,$attrs) = splice @cols,0,2 ) {
1809 $col_counter++;
1810 $self->_pod( $class, '=head2 ' . $name );
1811 $self->_pod( $class,
1812 join "\n", map {
1813 my $s = $attrs->{$_};
fca5431b 1814 $s = !defined $s ? 'undef' :
1815 length($s) == 0 ? '(empty string)' :
f170d55b 1816 ref($s) eq 'SCALAR' ? $$s :
1817 ref($s) ? do {
1818 my $dd = Dumper;
1819 $dd->Indent(0);
1820 $dd->Values([$s]);
1821 $dd->Dump;
1822 } :
1823 looks_like_number($s) ? $s :
1824 qq{'$s'}
fca5431b 1825 ;
79a00530 1826
1827 " $_: $s"
1828 } sort keys %$attrs,
1829 );
1830
1831 if( $self->can('_column_comment')
1832 and my $comment = $self->_column_comment( $self->{_class2table}{$class}, $col_counter)
1833 ) {
1834 $self->_pod( $class, $comment );
1835 }
fbcfebdd 1836 }
1837 $self->_pod_cut( $class );
1838 } elsif ( $method =~ /^(belongs_to|has_many|might_have)$/ ) {
1839 $self->_pod( $class, "=head1 RELATIONS" ) unless $self->{_relations_started} { $class } ;
1840 my ( $accessor, $rel_class ) = @_;
1841 $self->_pod( $class, "=head2 $accessor" );
1842 $self->_pod( $class, 'Type: ' . $method );
1843 $self->_pod( $class, "Related object: L<$rel_class>" );
1844 $self->_pod_cut( $class );
1845 $self->{_relations_started} { $class } = 1;
1846 }
996be9ee 1847}
1848
fbcfebdd 1849# Stores a POD documentation
1850sub _pod {
1851 my ($self, $class, $stmt) = @_;
1852 $self->_raw_stmt( $class, "\n" . $stmt );
1853}
1854
1855sub _pod_cut {
1856 my ($self, $class ) = @_;
1857 $self->_raw_stmt( $class, "\n=cut\n" );
1858}
1859
996be9ee 1860# Store a raw source line for a class (for dumping purposes)
1861sub _raw_stmt {
1862 my ($self, $class, $stmt) = @_;
af31090c 1863 push(@{$self->{_dump_storage}->{$class}}, $stmt);
996be9ee 1864}
1865
7cab3ab7 1866# Like above, but separately for the externally loaded stuff
1867sub _ext_stmt {
1868 my ($self, $class, $stmt) = @_;
af31090c 1869 push(@{$self->{_ext_storage}->{$class}}, $stmt);
7cab3ab7 1870}
1871
565335e6 1872sub _quote_table_name {
1873 my ($self, $table) = @_;
1874
1875 my $qt = $self->schema->storage->sql_maker->quote_char;
1876
c177d483 1877 return $table unless $qt;
1878
565335e6 1879 if (ref $qt) {
1880 return $qt->[0] . $table . $qt->[1];
1881 }
1882
1883 return $qt . $table . $qt;
1884}
1885
b639d969 1886sub _custom_column_info {
23d1f36b 1887 my ( $self, $table_name, $column_name, $column_info ) = @_;
b639d969 1888
d67d058e 1889 if (my $code = $self->custom_column_info) {
1890 return $code->($table_name, $column_name, $column_info) || {};
b639d969 1891 }
3a368709 1892 return {};
b639d969 1893}
1894
42e785fa 1895sub _datetime_column_info {
23d1f36b 1896 my ( $self, $table_name, $column_name, $column_info ) = @_;
d67d058e 1897 my $result = {};
1898 my $type = $column_info->{data_type} || '';
1899 if ((grep $_, @{ $column_info }{map "inflate_$_", qw/date datetime timestamp/})
1900 or ($type =~ /date|timestamp/i)) {
1901 $result->{timezone} = $self->datetime_timezone if $self->datetime_timezone;
1902 $result->{locale} = $self->datetime_locale if $self->datetime_locale;
42e785fa 1903 }
d67d058e 1904 return $result;
42e785fa 1905}
1906
bc1cb85e 1907sub _lc {
1908 my ($self, $name) = @_;
1909
1910 return $self->preserve_case ? $name : lc($name);
1911}
1912
1913sub _uc {
1914 my ($self, $name) = @_;
1915
1916 return $self->preserve_case ? $name : uc($name);
1917}
1918
0c1d5b47 1919sub _unregister_source_for_table {
1920 my ($self, $table) = @_;
1921
1922 eval {
1923 local $@;
1924 my $schema = $self->schema;
1925 # in older DBIC it's a private method
1926 my $unregister = $schema->can('unregister_source') || $schema->can('_unregister_source');
1927 $schema->$unregister($self->_table2moniker($table));
1928 delete $self->monikers->{$table};
1929 delete $self->classes->{$table};
1930 delete $self->_upgrading_classes->{$table};
1931 delete $self->{_tables}{$table};
1932 };
1933}
1934
ffc705f3 1935# remove the dump dir from @INC on destruction
1936sub DESTROY {
1937 my $self = shift;
1938
1939 @INC = grep $_ ne $self->dump_directory, @INC;
1940}
1941
996be9ee 1942=head2 monikers
1943
8f9d7ce5 1944Returns a hashref of loaded table to moniker mappings. There will
996be9ee 1945be two entries for each table, the original name and the "normalized"
1946name, in the case that the two are different (such as databases
1947that like uppercase table names, or preserve your original mixed-case
1948definitions, or what-have-you).
1949
1950=head2 classes
1951
8f9d7ce5 1952Returns a hashref of table to class mappings. In some cases it will
996be9ee 1953contain multiple entries per table for the original and normalized table
1954names, as above in L</monikers>.
1955
1956=head1 SEE ALSO
1957
1958L<DBIx::Class::Schema::Loader>
1959
be80bba7 1960=head1 AUTHOR
1961
9cc8e7e1 1962See L<DBIx::Class::Schema::Loader/AUTHOR> and L<DBIx::Class::Schema::Loader/CONTRIBUTORS>.
be80bba7 1963
1964=head1 LICENSE
1965
1966This library is free software; you can redistribute it and/or modify it under
1967the same terms as Perl itself.
1968
996be9ee 1969=cut
1970
19711;
bfb43060 1972# vim:et sts=4 sw=4 tw=0: