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