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