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