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