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