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