backcompat common tests now pass
[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
442 do $real_inc_path;
443 die $@ if $@;
996be9ee 444}
445
446=head2 load
447
448Does the actual schema-construction work.
449
450=cut
451
452sub load {
453 my $self = shift;
454
b97c2c1e 455 $self->_load_tables($self->_tables_list);
456}
457
458=head2 rescan
459
a60b5b8d 460Arguments: schema
461
b97c2c1e 462Rescan the database for newly added tables. Does
a60b5b8d 463not process drops or changes. Returns a list of
464the newly added table monikers.
465
466The schema argument should be the schema class
467or object to be affected. It should probably
468be derived from the original schema_class used
469during L</load>.
b97c2c1e 470
471=cut
472
473sub rescan {
a60b5b8d 474 my ($self, $schema) = @_;
475
476 $self->{schema} = $schema;
7824616e 477 $self->_relbuilder->{schema} = $schema;
b97c2c1e 478
479 my @created;
480 my @current = $self->_tables_list;
481 foreach my $table ($self->_tables_list) {
482 if(!exists $self->{_tables}->{$table}) {
483 push(@created, $table);
484 }
485 }
486
c39e3507 487 my $loaded = $self->_load_tables(@created);
a60b5b8d 488
c39e3507 489 return map { $self->monikers->{$_} } @$loaded;
b97c2c1e 490}
491
7824616e 492sub _relbuilder {
493 my ($self) = @_;
3fed44ca 494
495 return if $self->{skip_relationships};
496
7824616e 497 $self->{relbuilder} ||= DBIx::Class::Schema::Loader::RelBuilder->new(
498 $self->schema, $self->inflect_plural, $self->inflect_singular
499 );
500}
501
b97c2c1e 502sub _load_tables {
503 my ($self, @tables) = @_;
504
f96ef30f 505 # First, use _tables_list with constraint and exclude
506 # to get a list of tables to operate on
507
508 my $constraint = $self->constraint;
509 my $exclude = $self->exclude;
f96ef30f 510
b97c2c1e 511 @tables = grep { /$constraint/ } @tables if $constraint;
512 @tables = grep { ! /$exclude/ } @tables if $exclude;
f96ef30f 513
b97c2c1e 514 # Save the new tables to the tables list
a60b5b8d 515 foreach (@tables) {
516 $self->{_tables}->{$_} = 1;
517 }
f96ef30f 518
af31090c 519 $self->_make_src_class($_) for @tables;
f96ef30f 520 $self->_setup_src_meta($_) for @tables;
521
e8ad6491 522 if(!$self->skip_relationships) {
181cc907 523 # The relationship loader needs a working schema
af31090c 524 $self->{quiet} = 1;
79193756 525 local $self->{dump_directory} = $self->{temp_directory};
106a976a 526 $self->_reload_classes(\@tables);
e8ad6491 527 $self->_load_relationships($_) for @tables;
af31090c 528 $self->{quiet} = 0;
79193756 529
530 # Remove that temp dir from INC so it doesn't get reloaded
531 @INC = grep { $_ ne $self->{dump_directory} } @INC;
e8ad6491 532 }
533
f96ef30f 534 $self->_load_external($_)
75451704 535 for map { $self->classes->{$_} } @tables;
f96ef30f 536
106a976a 537 # Reload without unloading first to preserve any symbols from external
538 # packages.
539 $self->_reload_classes(\@tables, 0);
996be9ee 540
5223f24a 541 # Drop temporary cache
542 delete $self->{_cache};
543
c39e3507 544 return \@tables;
996be9ee 545}
546
af31090c 547sub _reload_classes {
106a976a 548 my ($self, $tables, $unload) = @_;
549
550 my @tables = @$tables;
551 $unload = 1 unless defined $unload;
181cc907 552
4daef04f 553 # so that we don't repeat custom sections
554 @INC = grep $_ ne $self->dump_directory, @INC;
555
181cc907 556 $self->_dump_to_dir(map { $self->classes->{$_} } @tables);
e9b8719e 557
558 unshift @INC, $self->dump_directory;
af31090c 559
706ef173 560 my @to_register;
561 my %have_source = map { $_ => $self->schema->source($_) }
562 $self->schema->sources;
563
181cc907 564 for my $table (@tables) {
565 my $moniker = $self->monikers->{$table};
566 my $class = $self->classes->{$table};
0ae6b65d 567
568 {
569 no warnings 'redefine';
570 local *Class::C3::reinitialize = sub {};
571 use warnings;
572
106a976a 573 Class::Unload->unload($class) if $unload;
706ef173 574 my ($source, $resultset_class);
575 if (
576 ($source = $have_source{$moniker})
577 && ($resultset_class = $source->resultset_class)
578 && ($resultset_class ne 'DBIx::Class::ResultSet')
579 ) {
580 my $has_file = Class::Inspector->loaded_filename($resultset_class);
106a976a 581 Class::Unload->unload($resultset_class) if $unload;
582 $self->_reload_class($resultset_class) if $has_file;
0ae6b65d 583 }
106a976a 584 $self->_reload_class($class);
af31090c 585 }
706ef173 586 push @to_register, [$moniker, $class];
587 }
af31090c 588
706ef173 589 Class::C3->reinitialize;
590 for (@to_register) {
591 $self->schema->register_class(@$_);
af31090c 592 }
593}
594
106a976a 595# We use this instead of ensure_class_loaded when there are package symbols we
596# want to preserve.
597sub _reload_class {
598 my ($self, $class) = @_;
599
600 my $class_path = $self->_class_path($class);
601 delete $INC{ $class_path };
602 eval "require $class;";
603}
604
996be9ee 605sub _get_dump_filename {
606 my ($self, $class) = (@_);
607
608 $class =~ s{::}{/}g;
609 return $self->dump_directory . q{/} . $class . q{.pm};
610}
611
612sub _ensure_dump_subdirs {
613 my ($self, $class) = (@_);
614
615 my @name_parts = split(/::/, $class);
dd03ee1a 616 pop @name_parts; # we don't care about the very last element,
617 # which is a filename
618
996be9ee 619 my $dir = $self->dump_directory;
7cab3ab7 620 while (1) {
621 if(!-d $dir) {
25328cc4 622 mkdir($dir) or croak "mkdir('$dir') failed: $!";
996be9ee 623 }
7cab3ab7 624 last if !@name_parts;
625 $dir = File::Spec->catdir($dir, shift @name_parts);
996be9ee 626 }
627}
628
629sub _dump_to_dir {
af31090c 630 my ($self, @classes) = @_;
996be9ee 631
fc2b71fd 632 my $schema_class = $self->schema_class;
9c9c2f2b 633 my $schema_base_class = $self->schema_base_class || 'DBIx::Class::Schema';
996be9ee 634
e9b8719e 635 my $target_dir = $self->dump_directory;
af31090c 636 warn "Dumping manual schema for $schema_class to directory $target_dir ...\n"
637 unless $self->{dynamic} or $self->{quiet};
996be9ee 638
7cab3ab7 639 my $schema_text =
640 qq|package $schema_class;\n\n|
b4dcbcc5 641 . qq|# Created by DBIx::Class::Schema::Loader\n|
642 . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|
7cab3ab7 643 . qq|use strict;\nuse warnings;\n\n|
9c9c2f2b 644 . qq|use base '$schema_base_class';\n\n|;
f44ecc2f 645
f44ecc2f 646 if ($self->use_namespaces) {
647 $schema_text .= qq|__PACKAGE__->load_namespaces|;
648 my $namespace_options;
649 for my $attr (qw(result_namespace
650 resultset_namespace
651 default_resultset_class)) {
652 if ($self->$attr) {
653 $namespace_options .= qq| $attr => '| . $self->$attr . qq|',\n|
654 }
655 }
656 $schema_text .= qq|(\n$namespace_options)| if $namespace_options;
657 $schema_text .= qq|;\n|;
658 }
659 else {
660 $schema_text .= qq|__PACKAGE__->load_classes;\n|;
f44ecc2f 661 }
996be9ee 662
7cab3ab7 663 $self->_write_classfile($schema_class, $schema_text);
996be9ee 664
9c9c2f2b 665 my $result_base_class = $self->result_base_class || 'DBIx::Class';
666
af31090c 667 foreach my $src_class (@classes) {
7cab3ab7 668 my $src_text =
669 qq|package $src_class;\n\n|
b4dcbcc5 670 . qq|# Created by DBIx::Class::Schema::Loader\n|
671 . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|
7cab3ab7 672 . qq|use strict;\nuse warnings;\n\n|
9c9c2f2b 673 . qq|use base '$result_base_class';\n\n|;
996be9ee 674
7cab3ab7 675 $self->_write_classfile($src_class, $src_text);
02356864 676 }
996be9ee 677
af31090c 678 warn "Schema dump completed.\n" unless $self->{dynamic} or $self->{quiet};
679
7cab3ab7 680}
681
79193756 682sub _sig_comment {
683 my ($self, $version, $ts) = @_;
684 return qq|\n\n# Created by DBIx::Class::Schema::Loader|
685 . qq| v| . $version
686 . q| @ | . $ts
687 . qq|\n# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:|;
688}
689
7cab3ab7 690sub _write_classfile {
691 my ($self, $class, $text) = @_;
692
693 my $filename = $self->_get_dump_filename($class);
694 $self->_ensure_dump_subdirs($class);
695
28b4691d 696 if (-f $filename && $self->really_erase_my_files) {
7cab3ab7 697 warn "Deleting existing file '$filename' due to "
af31090c 698 . "'really_erase_my_files' setting\n" unless $self->{quiet};
7cab3ab7 699 unlink($filename);
700 }
701
79193756 702 my ($custom_content, $old_md5, $old_ver, $old_ts) = $self->_get_custom_content($class, $filename);
17ca645f 703
7cab3ab7 704 $text .= qq|$_\n|
705 for @{$self->{_dump_storage}->{$class} || []};
706
79193756 707 # Check and see if the dump is infact differnt
708
709 my $compare_to;
710 if ($old_md5) {
711 $compare_to = $text . $self->_sig_comment($old_ver, $old_ts);
712
713
714 if (Digest::MD5::md5_base64($compare_to) eq $old_md5) {
715 return;
716 }
717 }
718
719 $text .= $self->_sig_comment(
01012543 720 $self->version_to_dump,
79193756 721 POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime)
722 );
7cab3ab7 723
724 open(my $fh, '>', $filename)
725 or croak "Cannot open '$filename' for writing: $!";
726
727 # Write the top half and its MD5 sum
a4476f41 728 print $fh $text . Digest::MD5::md5_base64($text) . "\n";
7cab3ab7 729
730 # Write out anything loaded via external partial class file in @INC
731 print $fh qq|$_\n|
732 for @{$self->{_ext_storage}->{$class} || []};
733
1eea4fb1 734 # Write out any custom content the user has added
7cab3ab7 735 print $fh $custom_content;
736
737 close($fh)
e9b8719e 738 or croak "Error closing '$filename': $!";
7cab3ab7 739}
740
79193756 741sub _default_custom_content {
742 return qq|\n\n# You can replace this text with custom|
743 . qq| content, and it will be preserved on regeneration|
744 . qq|\n1;\n|;
745}
746
7cab3ab7 747sub _get_custom_content {
748 my ($self, $class, $filename) = @_;
749
79193756 750 return ($self->_default_custom_content) if ! -f $filename;
751
7cab3ab7 752 open(my $fh, '<', $filename)
753 or croak "Cannot open '$filename' for reading: $!";
754
755 my $mark_re =
419a2eeb 756 qr{^(# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:)([A-Za-z0-9/+]{22})\n};
7cab3ab7 757
7cab3ab7 758 my $buffer = '';
79193756 759 my ($md5, $ts, $ver);
7cab3ab7 760 while(<$fh>) {
79193756 761 if(!$md5 && /$mark_re/) {
762 $md5 = $2;
763 my $line = $1;
764
765 # Pull out the previous version and timestamp
766 ($ver, $ts) = $buffer =~ m/# Created by DBIx::Class::Schema::Loader v(.*?) @ (.*?)$/s;
767
768 $buffer .= $line;
7cab3ab7 769 croak "Checksum mismatch in '$filename'"
79193756 770 if Digest::MD5::md5_base64($buffer) ne $md5;
7cab3ab7 771
772 $buffer = '';
773 }
774 else {
775 $buffer .= $_;
776 }
996be9ee 777 }
778
28b4691d 779 croak "Cannot not overwrite '$filename' without 'really_erase_my_files',"
419a2eeb 780 . " it does not appear to have been generated by Loader"
79193756 781 if !$md5;
5ef3c771 782
79193756 783 # Default custom content:
784 $buffer ||= $self->_default_custom_content;
5ef3c771 785
79193756 786 return ($buffer, $md5, $ver, $ts);
996be9ee 787}
788
789sub _use {
790 my $self = shift;
791 my $target = shift;
792
793 foreach (@_) {
cb54990b 794 warn "$target: use $_;" if $self->debug;
996be9ee 795 $self->_raw_stmt($target, "use $_;");
996be9ee 796 }
797}
798
799sub _inject {
800 my $self = shift;
801 my $target = shift;
802 my $schema_class = $self->schema_class;
803
af31090c 804 my $blist = join(q{ }, @_);
805 warn "$target: use base qw/ $blist /;" if $self->debug && @_;
806 $self->_raw_stmt($target, "use base qw/ $blist /;") if @_;
996be9ee 807}
808
f96ef30f 809# Create class with applicable bases, setup monikers, etc
810sub _make_src_class {
811 my ($self, $table) = @_;
996be9ee 812
a13b2803 813 my $schema = $self->schema;
814 my $schema_class = $self->schema_class;
996be9ee 815
f96ef30f 816 my $table_moniker = $self->_table2moniker($table);
f44ecc2f 817 my @result_namespace = ($schema_class);
818 if ($self->use_namespaces) {
819 my $result_namespace = $self->result_namespace || 'Result';
820 if ($result_namespace =~ /^\+(.*)/) {
821 # Fully qualified namespace
822 @result_namespace = ($1)
823 }
824 else {
825 # Relative namespace
826 push @result_namespace, $result_namespace;
827 }
828 }
829 my $table_class = join(q{::}, @result_namespace, $table_moniker);
996be9ee 830
f96ef30f 831 my $table_normalized = lc $table;
832 $self->classes->{$table} = $table_class;
833 $self->classes->{$table_normalized} = $table_class;
834 $self->monikers->{$table} = $table_moniker;
835 $self->monikers->{$table_normalized} = $table_moniker;
996be9ee 836
f96ef30f 837 $self->_use ($table_class, @{$self->additional_classes});
af31090c 838 $self->_inject($table_class, @{$self->left_base_classes});
996be9ee 839
605fcea8 840 $self->_dbic_stmt($table_class, 'load_components', @{$self->components}, 'Core');
996be9ee 841
f96ef30f 842 $self->_dbic_stmt($table_class, 'load_resultset_components', @{$self->resultset_components})
843 if @{$self->resultset_components};
af31090c 844 $self->_inject($table_class, @{$self->additional_base_classes});
f96ef30f 845}
996be9ee 846
af31090c 847# Set up metadata (cols, pks, etc)
f96ef30f 848sub _setup_src_meta {
849 my ($self, $table) = @_;
996be9ee 850
f96ef30f 851 my $schema = $self->schema;
852 my $schema_class = $self->schema_class;
a13b2803 853
f96ef30f 854 my $table_class = $self->classes->{$table};
855 my $table_moniker = $self->monikers->{$table};
996be9ee 856
ff30991a 857 my $table_name = $table;
858 my $name_sep = $self->schema->storage->sql_maker->name_sep;
859
c177d483 860 if ($name_sep && $table_name =~ /\Q$name_sep\E/) {
ff30991a 861 $table_name = \ $self->_quote_table_name($table_name);
862 }
863
864 $self->_dbic_stmt($table_class,'table',$table_name);
996be9ee 865
f96ef30f 866 my $cols = $self->_table_columns($table);
867 my $col_info;
868 eval { $col_info = $self->_columns_info_for($table) };
869 if($@) {
870 $self->_dbic_stmt($table_class,'add_columns',@$cols);
871 }
872 else {
0906d55b 873 if ($self->_is_case_sensitive) {
874 for my $col (keys %$col_info) {
875 $col_info->{$col}{accessor} = lc $col
876 if $col ne lc($col);
877 }
878 } else {
879 $col_info = { map { lc($_), $col_info->{$_} } keys %$col_info };
c9373b79 880 }
881
e7213f4f 882 my $fks = $self->_table_fk_info($table);
565335e6 883
e7213f4f 884 for my $fkdef (@$fks) {
885 for my $col (@{ $fkdef->{local_columns} }) {
565335e6 886 $col_info->{$col}{is_foreign_key} = 1;
e7213f4f 887 }
888 }
f96ef30f 889 $self->_dbic_stmt(
890 $table_class,
891 'add_columns',
565335e6 892 map { $_, ($col_info->{$_}||{}) } @$cols
f96ef30f 893 );
996be9ee 894 }
895
d70c335f 896 my %uniq_tag; # used to eliminate duplicate uniqs
897
f96ef30f 898 my $pks = $self->_table_pk_info($table) || [];
899 @$pks ? $self->_dbic_stmt($table_class,'set_primary_key',@$pks)
900 : carp("$table has no primary key");
d70c335f 901 $uniq_tag{ join("\0", @$pks) }++ if @$pks; # pk is a uniq
996be9ee 902
f96ef30f 903 my $uniqs = $self->_table_uniq_info($table) || [];
d70c335f 904 for (@$uniqs) {
905 my ($name, $cols) = @$_;
906 next if $uniq_tag{ join("\0", @$cols) }++; # skip duplicates
907 $self->_dbic_stmt($table_class,'add_unique_constraint', $name, $cols);
908 }
909
996be9ee 910}
911
912=head2 tables
913
914Returns a sorted list of loaded tables, using the original database table
915names.
916
917=cut
918
919sub tables {
920 my $self = shift;
921
b97c2c1e 922 return keys %{$self->_tables};
996be9ee 923}
924
925# Make a moniker from a table
c39e403e 926sub _default_table2moniker {
927 my ($self, $table) = @_;
928
929 return join '', map ucfirst, split /[\W_]+/,
930 Lingua::EN::Inflect::Number::to_S(lc $table);
931}
932
996be9ee 933sub _table2moniker {
934 my ( $self, $table ) = @_;
935
936 my $moniker;
937
938 if( ref $self->moniker_map eq 'HASH' ) {
939 $moniker = $self->moniker_map->{$table};
940 }
941 elsif( ref $self->moniker_map eq 'CODE' ) {
942 $moniker = $self->moniker_map->($table);
943 }
944
c39e403e 945 $moniker ||= $self->_default_table2moniker($table);
996be9ee 946
947 return $moniker;
948}
949
950sub _load_relationships {
e8ad6491 951 my ($self, $table) = @_;
996be9ee 952
e8ad6491 953 my $tbl_fk_info = $self->_table_fk_info($table);
954 foreach my $fkdef (@$tbl_fk_info) {
955 $fkdef->{remote_source} =
956 $self->monikers->{delete $fkdef->{remote_table}};
996be9ee 957 }
26f1c8c9 958 my $tbl_uniq_info = $self->_table_uniq_info($table);
996be9ee 959
e8ad6491 960 my $local_moniker = $self->monikers->{$table};
7824616e 961 my $rel_stmts = $self->_relbuilder->generate_code($local_moniker, $tbl_fk_info, $tbl_uniq_info);
996be9ee 962
996be9ee 963 foreach my $src_class (sort keys %$rel_stmts) {
964 my $src_stmts = $rel_stmts->{$src_class};
965 foreach my $stmt (@$src_stmts) {
966 $self->_dbic_stmt($src_class,$stmt->{method},@{$stmt->{args}});
967 }
968 }
969}
970
971# Overload these in driver class:
972
973# Returns an arrayref of column names
974sub _table_columns { croak "ABSTRACT METHOD" }
975
976# Returns arrayref of pk col names
977sub _table_pk_info { croak "ABSTRACT METHOD" }
978
979# Returns an arrayref of uniqs [ [ foo => [ col1, col2 ] ], [ bar => [ ... ] ] ]
980sub _table_uniq_info { croak "ABSTRACT METHOD" }
981
982# Returns an arrayref of foreign key constraints, each
983# being a hashref with 3 keys:
984# local_columns (arrayref), remote_columns (arrayref), remote_table
985sub _table_fk_info { croak "ABSTRACT METHOD" }
986
987# Returns an array of lower case table names
988sub _tables_list { croak "ABSTRACT METHOD" }
989
990# Execute a constructive DBIC class method, with debug/dump_to_dir hooks.
991sub _dbic_stmt {
992 my $self = shift;
993 my $class = shift;
994 my $method = shift;
995
996be9ee 996 my $args = dump(@_);
997 $args = '(' . $args . ')' if @_ < 2;
998 my $stmt = $method . $args . q{;};
999
1000 warn qq|$class\->$stmt\n| if $self->debug;
996be9ee 1001 $self->_raw_stmt($class, '__PACKAGE__->' . $stmt);
1002}
1003
1004# Store a raw source line for a class (for dumping purposes)
1005sub _raw_stmt {
1006 my ($self, $class, $stmt) = @_;
af31090c 1007 push(@{$self->{_dump_storage}->{$class}}, $stmt);
996be9ee 1008}
1009
7cab3ab7 1010# Like above, but separately for the externally loaded stuff
1011sub _ext_stmt {
1012 my ($self, $class, $stmt) = @_;
af31090c 1013 push(@{$self->{_ext_storage}->{$class}}, $stmt);
7cab3ab7 1014}
1015
565335e6 1016sub _quote_table_name {
1017 my ($self, $table) = @_;
1018
1019 my $qt = $self->schema->storage->sql_maker->quote_char;
1020
c177d483 1021 return $table unless $qt;
1022
565335e6 1023 if (ref $qt) {
1024 return $qt->[0] . $table . $qt->[1];
1025 }
1026
1027 return $qt . $table . $qt;
1028}
1029
1030sub _is_case_sensitive { 0 }
1031
996be9ee 1032=head2 monikers
1033
8f9d7ce5 1034Returns a hashref of loaded table to moniker mappings. There will
996be9ee 1035be two entries for each table, the original name and the "normalized"
1036name, in the case that the two are different (such as databases
1037that like uppercase table names, or preserve your original mixed-case
1038definitions, or what-have-you).
1039
1040=head2 classes
1041
8f9d7ce5 1042Returns a hashref of table to class mappings. In some cases it will
996be9ee 1043contain multiple entries per table for the original and normalized table
1044names, as above in L</monikers>.
1045
1046=head1 SEE ALSO
1047
1048L<DBIx::Class::Schema::Loader>
1049
be80bba7 1050=head1 AUTHOR
1051
1052See L<DBIx::Class::Schema::Loader/CONTRIBUTORS>.
1053
1054=head1 LICENSE
1055
1056This library is free software; you can redistribute it and/or modify it under
1057the same terms as Perl itself.
1058
996be9ee 1059=cut
1060
10611;