Merge 'back-compat' into 'current'
[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
294# ensure that a peice of object data is a valid arrayref, creating
295# an empty one or encapsulating whatever's there.
296sub _ensure_arrayref {
297 my $self = shift;
298
299 foreach (@_) {
300 $self->{$_} ||= [];
301 $self->{$_} = [ $self->{$_} ]
302 unless ref $self->{$_} eq 'ARRAY';
303 }
304}
305
306=head2 new
307
308Constructor for L<DBIx::Class::Schema::Loader::Base>, used internally
309by L<DBIx::Class::Schema::Loader>.
310
311=cut
312
313sub new {
314 my ( $class, %args ) = @_;
315
316 my $self = { %args };
317
318 bless $self => $class;
319
996be9ee 320 $self->_ensure_arrayref(qw/additional_classes
321 additional_base_classes
322 left_base_classes
323 components
324 resultset_components
325 /);
326
327 push(@{$self->{components}}, 'ResultSetManager')
328 if @{$self->{resultset_components}};
329
330 $self->{monikers} = {};
331 $self->{classes} = {};
332
996be9ee 333 $self->{schema_class} ||= ( ref $self->{schema} || $self->{schema} );
334 $self->{schema} ||= $self->{schema_class};
335
28b4691d 336 croak "dump_overwrite is deprecated. Please read the"
337 . " DBIx::Class::Schema::Loader::Base documentation"
338 if $self->{dump_overwrite};
339
af31090c 340 $self->{dynamic} = ! $self->{dump_directory};
79193756 341 $self->{temp_directory} ||= File::Temp::tempdir( 'dbicXXXX',
af31090c 342 TMPDIR => 1,
343 CLEANUP => 1,
344 );
345
79193756 346 $self->{dump_directory} ||= $self->{temp_directory};
347
01012543 348 $self->version_to_dump($DBIx::Class::Schema::Loader::VERSION);
1c95b304 349 $self->schema_version_to_dump($DBIx::Class::Schema::Loader::VERSION);
01012543 350
a8d229ff 351 if (not ref $self->naming && defined $self->naming) {
9cc8e7e1 352 my $naming_ver = $self->naming;
a8d229ff 353 $self->{naming} = {
354 relationships => $naming_ver,
355 monikers => $naming_ver,
356 };
357 }
358
7824616e 359 $self->_check_back_compat;
9c465d2c 360
7824616e 361 $self;
362}
af31090c 363
7824616e 364sub _check_back_compat {
365 my ($self) = @_;
e8ad6491 366
a8d229ff 367# dynamic schemas will always be in 0.04006 mode, unless overridden
106a976a 368 if ($self->dynamic) {
fb3bb595 369# just in case, though no one is likely to dump a dynamic schema
1c95b304 370 $self->schema_version_to_dump('0.04006');
a8d229ff 371
372 $self->naming->{relationships} ||= 'v4';
373 $self->naming->{monikers} ||= 'v4';
374
01012543 375 return;
376 }
377
378# otherwise check if we need backcompat mode for a static schema
7824616e 379 my $filename = $self->_get_dump_filename($self->schema_class);
380 return unless -e $filename;
381
382 open(my $fh, '<', $filename)
383 or croak "Cannot open '$filename' for reading: $!";
384
385 while (<$fh>) {
01012543 386 if (/^# Created by DBIx::Class::Schema::Loader v((\d+)\.(\d+))/) {
387 my $real_ver = $1;
a8d229ff 388
389 $self->schema_version_to_dump($real_ver);
390
391 # XXX when we go past .0 this will need fixing
392 my ($v) = $real_ver =~ /([1-9])/;
393 $v = "v$v";
394
395 $self->naming->{relationships} ||= $v;
396 $self->naming->{monikers} ||= $v;
397
7824616e 398 last;
399 }
400 }
401 close $fh;
996be9ee 402}
403
419a2eeb 404sub _find_file_in_inc {
405 my ($self, $file) = @_;
406
407 foreach my $prefix (@INC) {
af31090c 408 my $fullpath = File::Spec->catfile($prefix, $file);
409 return $fullpath if -f $fullpath
410 and Cwd::abs_path($fullpath) ne
411 Cwd::abs_path(File::Spec->catfile($self->dump_directory, $file)) || '';
419a2eeb 412 }
413
414 return;
415}
416
fb3bb595 417sub _class_path {
f96ef30f 418 my ($self, $class) = @_;
419
420 my $class_path = $class;
421 $class_path =~ s{::}{/}g;
422 $class_path .= '.pm';
423
fb3bb595 424 return $class_path;
425}
426
427sub _find_class_in_inc {
428 my ($self, $class) = @_;
429
430 return $self->_find_file_in_inc($self->_class_path($class));
431}
432
433sub _load_external {
434 my ($self, $class) = @_;
435
436 my $real_inc_path = $self->_find_class_in_inc($class);
f96ef30f 437
af31090c 438 return if !$real_inc_path;
f96ef30f 439
440 # If we make it to here, we loaded an external definition
441 warn qq/# Loaded external class definition for '$class'\n/
442 if $self->debug;
443
f96ef30f 444 open(my $fh, '<', $real_inc_path)
445 or croak "Failed to open '$real_inc_path' for reading: $!";
446 $self->_ext_stmt($class,
565ca24d 447 qq|# These lines were loaded from '$real_inc_path' found in \@INC.\n|
448 .qq|# They are now part of the custom portion of this file\n|
449 .qq|# for you to hand-edit. If you do not either delete\n|
450 .qq|# this section or remove that file from \@INC, this section\n|
451 .qq|# will be repeated redundantly when you re-create this\n|
452 .qq|# file again via Loader!\n|
f96ef30f 453 );
454 while(<$fh>) {
455 chomp;
456 $self->_ext_stmt($class, $_);
996be9ee 457 }
f96ef30f 458 $self->_ext_stmt($class,
70b72fab 459 qq|# End of lines loaded from '$real_inc_path' |
f96ef30f 460 );
461 close($fh)
462 or croak "Failed to close $real_inc_path: $!";
106a976a 463
dd5f03fc 464 if ($self->dynamic) { # load the class too
9e8033c1 465 # turn off redefined warnings
dd5f03fc 466 local $SIG{__WARN__} = sub {};
9e8033c1 467 do $real_inc_path;
dd5f03fc 468 die $@ if $@;
9e8033c1 469 }
996be9ee 470}
471
472=head2 load
473
474Does the actual schema-construction work.
475
476=cut
477
478sub load {
479 my $self = shift;
480
b97c2c1e 481 $self->_load_tables($self->_tables_list);
482}
483
484=head2 rescan
485
a60b5b8d 486Arguments: schema
487
b97c2c1e 488Rescan the database for newly added tables. Does
a60b5b8d 489not process drops or changes. Returns a list of
490the newly added table monikers.
491
492The schema argument should be the schema class
493or object to be affected. It should probably
494be derived from the original schema_class used
495during L</load>.
b97c2c1e 496
497=cut
498
499sub rescan {
a60b5b8d 500 my ($self, $schema) = @_;
501
502 $self->{schema} = $schema;
7824616e 503 $self->_relbuilder->{schema} = $schema;
b97c2c1e 504
505 my @created;
506 my @current = $self->_tables_list;
507 foreach my $table ($self->_tables_list) {
508 if(!exists $self->{_tables}->{$table}) {
509 push(@created, $table);
510 }
511 }
512
c39e3507 513 my $loaded = $self->_load_tables(@created);
a60b5b8d 514
c39e3507 515 return map { $self->monikers->{$_} } @$loaded;
b97c2c1e 516}
517
7824616e 518sub _relbuilder {
519 my ($self) = @_;
3fed44ca 520
521 return if $self->{skip_relationships};
522
a8d229ff 523 if ($self->naming->{relationships} eq 'v4') {
524 require DBIx::Class::Schema::Loader::RelBuilder::Compat::v0_040;
525 return $self->{relbuilder} ||=
526 DBIx::Class::Schema::Loader::RelBuilder::Compat::v0_040->new(
527 $self->schema, $self->inflect_plural, $self->inflect_singular
528 );
529 }
530
7824616e 531 $self->{relbuilder} ||= DBIx::Class::Schema::Loader::RelBuilder->new(
532 $self->schema, $self->inflect_plural, $self->inflect_singular
533 );
534}
535
b97c2c1e 536sub _load_tables {
537 my ($self, @tables) = @_;
538
f96ef30f 539 # First, use _tables_list with constraint and exclude
540 # to get a list of tables to operate on
541
542 my $constraint = $self->constraint;
543 my $exclude = $self->exclude;
f96ef30f 544
b97c2c1e 545 @tables = grep { /$constraint/ } @tables if $constraint;
546 @tables = grep { ! /$exclude/ } @tables if $exclude;
f96ef30f 547
b97c2c1e 548 # Save the new tables to the tables list
a60b5b8d 549 foreach (@tables) {
550 $self->{_tables}->{$_} = 1;
551 }
f96ef30f 552
af31090c 553 $self->_make_src_class($_) for @tables;
f96ef30f 554 $self->_setup_src_meta($_) for @tables;
555
e8ad6491 556 if(!$self->skip_relationships) {
181cc907 557 # The relationship loader needs a working schema
af31090c 558 $self->{quiet} = 1;
79193756 559 local $self->{dump_directory} = $self->{temp_directory};
106a976a 560 $self->_reload_classes(\@tables);
e8ad6491 561 $self->_load_relationships($_) for @tables;
af31090c 562 $self->{quiet} = 0;
79193756 563
564 # Remove that temp dir from INC so it doesn't get reloaded
565 @INC = grep { $_ ne $self->{dump_directory} } @INC;
e8ad6491 566 }
567
f96ef30f 568 $self->_load_external($_)
75451704 569 for map { $self->classes->{$_} } @tables;
f96ef30f 570
106a976a 571 # Reload without unloading first to preserve any symbols from external
572 # packages.
573 $self->_reload_classes(\@tables, 0);
996be9ee 574
5223f24a 575 # Drop temporary cache
576 delete $self->{_cache};
577
c39e3507 578 return \@tables;
996be9ee 579}
580
af31090c 581sub _reload_classes {
106a976a 582 my ($self, $tables, $unload) = @_;
583
584 my @tables = @$tables;
585 $unload = 1 unless defined $unload;
181cc907 586
4daef04f 587 # so that we don't repeat custom sections
588 @INC = grep $_ ne $self->dump_directory, @INC;
589
181cc907 590 $self->_dump_to_dir(map { $self->classes->{$_} } @tables);
e9b8719e 591
592 unshift @INC, $self->dump_directory;
af31090c 593
706ef173 594 my @to_register;
595 my %have_source = map { $_ => $self->schema->source($_) }
596 $self->schema->sources;
597
181cc907 598 for my $table (@tables) {
599 my $moniker = $self->monikers->{$table};
600 my $class = $self->classes->{$table};
0ae6b65d 601
602 {
603 no warnings 'redefine';
604 local *Class::C3::reinitialize = sub {};
605 use warnings;
606
106a976a 607 Class::Unload->unload($class) if $unload;
706ef173 608 my ($source, $resultset_class);
609 if (
610 ($source = $have_source{$moniker})
611 && ($resultset_class = $source->resultset_class)
612 && ($resultset_class ne 'DBIx::Class::ResultSet')
613 ) {
614 my $has_file = Class::Inspector->loaded_filename($resultset_class);
106a976a 615 Class::Unload->unload($resultset_class) if $unload;
616 $self->_reload_class($resultset_class) if $has_file;
0ae6b65d 617 }
106a976a 618 $self->_reload_class($class);
af31090c 619 }
706ef173 620 push @to_register, [$moniker, $class];
621 }
af31090c 622
706ef173 623 Class::C3->reinitialize;
624 for (@to_register) {
625 $self->schema->register_class(@$_);
af31090c 626 }
627}
628
106a976a 629# We use this instead of ensure_class_loaded when there are package symbols we
630# want to preserve.
631sub _reload_class {
632 my ($self, $class) = @_;
633
634 my $class_path = $self->_class_path($class);
635 delete $INC{ $class_path };
636 eval "require $class;";
637}
638
996be9ee 639sub _get_dump_filename {
640 my ($self, $class) = (@_);
641
642 $class =~ s{::}{/}g;
643 return $self->dump_directory . q{/} . $class . q{.pm};
644}
645
646sub _ensure_dump_subdirs {
647 my ($self, $class) = (@_);
648
649 my @name_parts = split(/::/, $class);
dd03ee1a 650 pop @name_parts; # we don't care about the very last element,
651 # which is a filename
652
996be9ee 653 my $dir = $self->dump_directory;
7cab3ab7 654 while (1) {
655 if(!-d $dir) {
25328cc4 656 mkdir($dir) or croak "mkdir('$dir') failed: $!";
996be9ee 657 }
7cab3ab7 658 last if !@name_parts;
659 $dir = File::Spec->catdir($dir, shift @name_parts);
996be9ee 660 }
661}
662
663sub _dump_to_dir {
af31090c 664 my ($self, @classes) = @_;
996be9ee 665
fc2b71fd 666 my $schema_class = $self->schema_class;
9c9c2f2b 667 my $schema_base_class = $self->schema_base_class || 'DBIx::Class::Schema';
996be9ee 668
e9b8719e 669 my $target_dir = $self->dump_directory;
af31090c 670 warn "Dumping manual schema for $schema_class to directory $target_dir ...\n"
671 unless $self->{dynamic} or $self->{quiet};
996be9ee 672
7cab3ab7 673 my $schema_text =
674 qq|package $schema_class;\n\n|
b4dcbcc5 675 . qq|# Created by DBIx::Class::Schema::Loader\n|
676 . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|
7cab3ab7 677 . qq|use strict;\nuse warnings;\n\n|
9c9c2f2b 678 . qq|use base '$schema_base_class';\n\n|;
f44ecc2f 679
f44ecc2f 680 if ($self->use_namespaces) {
681 $schema_text .= qq|__PACKAGE__->load_namespaces|;
682 my $namespace_options;
683 for my $attr (qw(result_namespace
684 resultset_namespace
685 default_resultset_class)) {
686 if ($self->$attr) {
687 $namespace_options .= qq| $attr => '| . $self->$attr . qq|',\n|
688 }
689 }
690 $schema_text .= qq|(\n$namespace_options)| if $namespace_options;
691 $schema_text .= qq|;\n|;
692 }
693 else {
694 $schema_text .= qq|__PACKAGE__->load_classes;\n|;
f44ecc2f 695 }
996be9ee 696
1c95b304 697 {
698 local $self->{version_to_dump} = $self->schema_version_to_dump;
699 $self->_write_classfile($schema_class, $schema_text);
700 }
996be9ee 701
2229729e 702 my $result_base_class = $self->result_base_class || 'DBIx::Class::Core';
9c9c2f2b 703
af31090c 704 foreach my $src_class (@classes) {
7cab3ab7 705 my $src_text =
706 qq|package $src_class;\n\n|
b4dcbcc5 707 . qq|# Created by DBIx::Class::Schema::Loader\n|
708 . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|
7cab3ab7 709 . qq|use strict;\nuse warnings;\n\n|
9c9c2f2b 710 . qq|use base '$result_base_class';\n\n|;
996be9ee 711
7cab3ab7 712 $self->_write_classfile($src_class, $src_text);
02356864 713 }
996be9ee 714
af31090c 715 warn "Schema dump completed.\n" unless $self->{dynamic} or $self->{quiet};
716
7cab3ab7 717}
718
79193756 719sub _sig_comment {
720 my ($self, $version, $ts) = @_;
721 return qq|\n\n# Created by DBIx::Class::Schema::Loader|
722 . qq| v| . $version
723 . q| @ | . $ts
724 . qq|\n# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:|;
725}
726
7cab3ab7 727sub _write_classfile {
728 my ($self, $class, $text) = @_;
729
730 my $filename = $self->_get_dump_filename($class);
731 $self->_ensure_dump_subdirs($class);
732
28b4691d 733 if (-f $filename && $self->really_erase_my_files) {
7cab3ab7 734 warn "Deleting existing file '$filename' due to "
af31090c 735 . "'really_erase_my_files' setting\n" unless $self->{quiet};
7cab3ab7 736 unlink($filename);
737 }
738
79193756 739 my ($custom_content, $old_md5, $old_ver, $old_ts) = $self->_get_custom_content($class, $filename);
17ca645f 740
7cab3ab7 741 $text .= qq|$_\n|
742 for @{$self->{_dump_storage}->{$class} || []};
743
79193756 744 # Check and see if the dump is infact differnt
745
746 my $compare_to;
747 if ($old_md5) {
748 $compare_to = $text . $self->_sig_comment($old_ver, $old_ts);
749
750
751 if (Digest::MD5::md5_base64($compare_to) eq $old_md5) {
752 return;
753 }
754 }
755
756 $text .= $self->_sig_comment(
01012543 757 $self->version_to_dump,
79193756 758 POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime)
759 );
7cab3ab7 760
761 open(my $fh, '>', $filename)
762 or croak "Cannot open '$filename' for writing: $!";
763
764 # Write the top half and its MD5 sum
a4476f41 765 print $fh $text . Digest::MD5::md5_base64($text) . "\n";
7cab3ab7 766
767 # Write out anything loaded via external partial class file in @INC
768 print $fh qq|$_\n|
769 for @{$self->{_ext_storage}->{$class} || []};
770
1eea4fb1 771 # Write out any custom content the user has added
7cab3ab7 772 print $fh $custom_content;
773
774 close($fh)
e9b8719e 775 or croak "Error closing '$filename': $!";
7cab3ab7 776}
777
79193756 778sub _default_custom_content {
779 return qq|\n\n# You can replace this text with custom|
780 . qq| content, and it will be preserved on regeneration|
781 . qq|\n1;\n|;
782}
783
7cab3ab7 784sub _get_custom_content {
785 my ($self, $class, $filename) = @_;
786
79193756 787 return ($self->_default_custom_content) if ! -f $filename;
788
7cab3ab7 789 open(my $fh, '<', $filename)
790 or croak "Cannot open '$filename' for reading: $!";
791
792 my $mark_re =
419a2eeb 793 qr{^(# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:)([A-Za-z0-9/+]{22})\n};
7cab3ab7 794
7cab3ab7 795 my $buffer = '';
79193756 796 my ($md5, $ts, $ver);
7cab3ab7 797 while(<$fh>) {
79193756 798 if(!$md5 && /$mark_re/) {
799 $md5 = $2;
800 my $line = $1;
801
802 # Pull out the previous version and timestamp
803 ($ver, $ts) = $buffer =~ m/# Created by DBIx::Class::Schema::Loader v(.*?) @ (.*?)$/s;
804
805 $buffer .= $line;
7cab3ab7 806 croak "Checksum mismatch in '$filename'"
79193756 807 if Digest::MD5::md5_base64($buffer) ne $md5;
7cab3ab7 808
809 $buffer = '';
810 }
811 else {
812 $buffer .= $_;
813 }
996be9ee 814 }
815
28b4691d 816 croak "Cannot not overwrite '$filename' without 'really_erase_my_files',"
419a2eeb 817 . " it does not appear to have been generated by Loader"
79193756 818 if !$md5;
5ef3c771 819
79193756 820 # Default custom content:
821 $buffer ||= $self->_default_custom_content;
5ef3c771 822
79193756 823 return ($buffer, $md5, $ver, $ts);
996be9ee 824}
825
826sub _use {
827 my $self = shift;
828 my $target = shift;
829
830 foreach (@_) {
cb54990b 831 warn "$target: use $_;" if $self->debug;
996be9ee 832 $self->_raw_stmt($target, "use $_;");
996be9ee 833 }
834}
835
836sub _inject {
837 my $self = shift;
838 my $target = shift;
839 my $schema_class = $self->schema_class;
840
af31090c 841 my $blist = join(q{ }, @_);
842 warn "$target: use base qw/ $blist /;" if $self->debug && @_;
843 $self->_raw_stmt($target, "use base qw/ $blist /;") if @_;
996be9ee 844}
845
f96ef30f 846# Create class with applicable bases, setup monikers, etc
847sub _make_src_class {
848 my ($self, $table) = @_;
996be9ee 849
a13b2803 850 my $schema = $self->schema;
851 my $schema_class = $self->schema_class;
996be9ee 852
f96ef30f 853 my $table_moniker = $self->_table2moniker($table);
f44ecc2f 854 my @result_namespace = ($schema_class);
855 if ($self->use_namespaces) {
856 my $result_namespace = $self->result_namespace || 'Result';
857 if ($result_namespace =~ /^\+(.*)/) {
858 # Fully qualified namespace
859 @result_namespace = ($1)
860 }
861 else {
862 # Relative namespace
863 push @result_namespace, $result_namespace;
864 }
865 }
866 my $table_class = join(q{::}, @result_namespace, $table_moniker);
996be9ee 867
f96ef30f 868 my $table_normalized = lc $table;
869 $self->classes->{$table} = $table_class;
870 $self->classes->{$table_normalized} = $table_class;
871 $self->monikers->{$table} = $table_moniker;
872 $self->monikers->{$table_normalized} = $table_moniker;
996be9ee 873
f96ef30f 874 $self->_use ($table_class, @{$self->additional_classes});
af31090c 875 $self->_inject($table_class, @{$self->left_base_classes});
996be9ee 876
2229729e 877 if (my @components = @{ $self->components }) {
878 $self->_dbic_stmt($table_class, 'load_components', @components);
879 }
996be9ee 880
f96ef30f 881 $self->_dbic_stmt($table_class, 'load_resultset_components', @{$self->resultset_components})
882 if @{$self->resultset_components};
af31090c 883 $self->_inject($table_class, @{$self->additional_base_classes});
f96ef30f 884}
996be9ee 885
af31090c 886# Set up metadata (cols, pks, etc)
f96ef30f 887sub _setup_src_meta {
888 my ($self, $table) = @_;
996be9ee 889
f96ef30f 890 my $schema = $self->schema;
891 my $schema_class = $self->schema_class;
a13b2803 892
f96ef30f 893 my $table_class = $self->classes->{$table};
894 my $table_moniker = $self->monikers->{$table};
996be9ee 895
ff30991a 896 my $table_name = $table;
897 my $name_sep = $self->schema->storage->sql_maker->name_sep;
898
c177d483 899 if ($name_sep && $table_name =~ /\Q$name_sep\E/) {
ff30991a 900 $table_name = \ $self->_quote_table_name($table_name);
901 }
902
903 $self->_dbic_stmt($table_class,'table',$table_name);
996be9ee 904
f96ef30f 905 my $cols = $self->_table_columns($table);
906 my $col_info;
907 eval { $col_info = $self->_columns_info_for($table) };
908 if($@) {
909 $self->_dbic_stmt($table_class,'add_columns',@$cols);
910 }
911 else {
0906d55b 912 if ($self->_is_case_sensitive) {
913 for my $col (keys %$col_info) {
914 $col_info->{$col}{accessor} = lc $col
915 if $col ne lc($col);
916 }
917 } else {
918 $col_info = { map { lc($_), $col_info->{$_} } keys %$col_info };
c9373b79 919 }
920
e7213f4f 921 my $fks = $self->_table_fk_info($table);
565335e6 922
e7213f4f 923 for my $fkdef (@$fks) {
924 for my $col (@{ $fkdef->{local_columns} }) {
565335e6 925 $col_info->{$col}{is_foreign_key} = 1;
e7213f4f 926 }
927 }
f96ef30f 928 $self->_dbic_stmt(
929 $table_class,
930 'add_columns',
565335e6 931 map { $_, ($col_info->{$_}||{}) } @$cols
f96ef30f 932 );
996be9ee 933 }
934
d70c335f 935 my %uniq_tag; # used to eliminate duplicate uniqs
936
f96ef30f 937 my $pks = $self->_table_pk_info($table) || [];
938 @$pks ? $self->_dbic_stmt($table_class,'set_primary_key',@$pks)
939 : carp("$table has no primary key");
d70c335f 940 $uniq_tag{ join("\0", @$pks) }++ if @$pks; # pk is a uniq
996be9ee 941
f96ef30f 942 my $uniqs = $self->_table_uniq_info($table) || [];
d70c335f 943 for (@$uniqs) {
944 my ($name, $cols) = @$_;
945 next if $uniq_tag{ join("\0", @$cols) }++; # skip duplicates
946 $self->_dbic_stmt($table_class,'add_unique_constraint', $name, $cols);
947 }
948
996be9ee 949}
950
951=head2 tables
952
953Returns a sorted list of loaded tables, using the original database table
954names.
955
956=cut
957
958sub tables {
959 my $self = shift;
960
b97c2c1e 961 return keys %{$self->_tables};
996be9ee 962}
963
964# Make a moniker from a table
c39e403e 965sub _default_table2moniker {
966 my ($self, $table) = @_;
967
a8d229ff 968 if ($self->naming->{monikers} eq 'v4') {
969 return join '', map ucfirst, split /[\W_]+/, lc $table;
970 }
971
c39e403e 972 return join '', map ucfirst, split /[\W_]+/,
973 Lingua::EN::Inflect::Number::to_S(lc $table);
974}
975
996be9ee 976sub _table2moniker {
977 my ( $self, $table ) = @_;
978
979 my $moniker;
980
981 if( ref $self->moniker_map eq 'HASH' ) {
982 $moniker = $self->moniker_map->{$table};
983 }
984 elsif( ref $self->moniker_map eq 'CODE' ) {
985 $moniker = $self->moniker_map->($table);
986 }
987
c39e403e 988 $moniker ||= $self->_default_table2moniker($table);
996be9ee 989
990 return $moniker;
991}
992
993sub _load_relationships {
e8ad6491 994 my ($self, $table) = @_;
996be9ee 995
e8ad6491 996 my $tbl_fk_info = $self->_table_fk_info($table);
997 foreach my $fkdef (@$tbl_fk_info) {
998 $fkdef->{remote_source} =
999 $self->monikers->{delete $fkdef->{remote_table}};
996be9ee 1000 }
26f1c8c9 1001 my $tbl_uniq_info = $self->_table_uniq_info($table);
996be9ee 1002
e8ad6491 1003 my $local_moniker = $self->monikers->{$table};
7824616e 1004 my $rel_stmts = $self->_relbuilder->generate_code($local_moniker, $tbl_fk_info, $tbl_uniq_info);
996be9ee 1005
996be9ee 1006 foreach my $src_class (sort keys %$rel_stmts) {
1007 my $src_stmts = $rel_stmts->{$src_class};
1008 foreach my $stmt (@$src_stmts) {
1009 $self->_dbic_stmt($src_class,$stmt->{method},@{$stmt->{args}});
1010 }
1011 }
1012}
1013
1014# Overload these in driver class:
1015
1016# Returns an arrayref of column names
1017sub _table_columns { croak "ABSTRACT METHOD" }
1018
1019# Returns arrayref of pk col names
1020sub _table_pk_info { croak "ABSTRACT METHOD" }
1021
1022# Returns an arrayref of uniqs [ [ foo => [ col1, col2 ] ], [ bar => [ ... ] ] ]
1023sub _table_uniq_info { croak "ABSTRACT METHOD" }
1024
1025# Returns an arrayref of foreign key constraints, each
1026# being a hashref with 3 keys:
1027# local_columns (arrayref), remote_columns (arrayref), remote_table
1028sub _table_fk_info { croak "ABSTRACT METHOD" }
1029
1030# Returns an array of lower case table names
1031sub _tables_list { croak "ABSTRACT METHOD" }
1032
1033# Execute a constructive DBIC class method, with debug/dump_to_dir hooks.
1034sub _dbic_stmt {
1035 my $self = shift;
1036 my $class = shift;
1037 my $method = shift;
fbcfebdd 1038 if ( $method eq 'table' ) {
1039 my ($table) = @_;
1040 $self->_pod( $class, "=head1 NAME" );
1041 my $table_descr = $class;
1042 if ( $self->can('_table_comment') ) {
1043 my $comment = $self->_table_comment($table);
1044 $table_descr .= " - " . $comment if $comment;
1045 }
1046 $self->{_class2table}{ $class } = $table;
1047 $self->_pod( $class, $table_descr );
1048 $self->_pod_cut( $class );
1049 } elsif ( $method eq 'add_columns' ) {
1050 $self->_pod( $class, "=head1 ACCESSORS" );
1051 my $i = 0;
1052 foreach ( @_ ) {
1053 $i++;
1054 next unless $i % 2;
1055 $self->_pod( $class, '=head2 ' . $_ );
1056 my $comment;
1057 $comment = $self->_column_comment( $self->{_class2table}{$class}, ($i - 1) / 2 + 1 ) if $self->can('_column_comment');
1058 $self->_pod( $class, $comment ) if $comment;
1059 }
1060 $self->_pod_cut( $class );
1061 } elsif ( $method =~ /^(belongs_to|has_many|might_have)$/ ) {
1062 $self->_pod( $class, "=head1 RELATIONS" ) unless $self->{_relations_started} { $class } ;
1063 my ( $accessor, $rel_class ) = @_;
1064 $self->_pod( $class, "=head2 $accessor" );
1065 $self->_pod( $class, 'Type: ' . $method );
1066 $self->_pod( $class, "Related object: L<$rel_class>" );
1067 $self->_pod_cut( $class );
1068 $self->{_relations_started} { $class } = 1;
1069 }
996be9ee 1070 my $args = dump(@_);
1071 $args = '(' . $args . ')' if @_ < 2;
1072 my $stmt = $method . $args . q{;};
1073
1074 warn qq|$class\->$stmt\n| if $self->debug;
996be9ee 1075 $self->_raw_stmt($class, '__PACKAGE__->' . $stmt);
fbcfebdd 1076 return;
996be9ee 1077}
1078
fbcfebdd 1079# Stores a POD documentation
1080sub _pod {
1081 my ($self, $class, $stmt) = @_;
1082 $self->_raw_stmt( $class, "\n" . $stmt );
1083}
1084
1085sub _pod_cut {
1086 my ($self, $class ) = @_;
1087 $self->_raw_stmt( $class, "\n=cut\n" );
1088}
1089
1090
996be9ee 1091# Store a raw source line for a class (for dumping purposes)
1092sub _raw_stmt {
1093 my ($self, $class, $stmt) = @_;
af31090c 1094 push(@{$self->{_dump_storage}->{$class}}, $stmt);
996be9ee 1095}
1096
7cab3ab7 1097# Like above, but separately for the externally loaded stuff
1098sub _ext_stmt {
1099 my ($self, $class, $stmt) = @_;
af31090c 1100 push(@{$self->{_ext_storage}->{$class}}, $stmt);
7cab3ab7 1101}
1102
565335e6 1103sub _quote_table_name {
1104 my ($self, $table) = @_;
1105
1106 my $qt = $self->schema->storage->sql_maker->quote_char;
1107
c177d483 1108 return $table unless $qt;
1109
565335e6 1110 if (ref $qt) {
1111 return $qt->[0] . $table . $qt->[1];
1112 }
1113
1114 return $qt . $table . $qt;
1115}
1116
1117sub _is_case_sensitive { 0 }
1118
996be9ee 1119=head2 monikers
1120
8f9d7ce5 1121Returns a hashref of loaded table to moniker mappings. There will
996be9ee 1122be two entries for each table, the original name and the "normalized"
1123name, in the case that the two are different (such as databases
1124that like uppercase table names, or preserve your original mixed-case
1125definitions, or what-have-you).
1126
1127=head2 classes
1128
8f9d7ce5 1129Returns a hashref of table to class mappings. In some cases it will
996be9ee 1130contain multiple entries per table for the original and normalized table
1131names, as above in L</monikers>.
1132
1133=head1 SEE ALSO
1134
1135L<DBIx::Class::Schema::Loader>
1136
be80bba7 1137=head1 AUTHOR
1138
9cc8e7e1 1139See L<DBIx::Class::Schema::Loader/AUTHOR> and L<DBIx::Class::Schema::Loader/CONTRIBUTORS>.
be80bba7 1140
1141=head1 LICENSE
1142
1143This library is free software; you can redistribute it and/or modify it under
1144the same terms as Perl itself.
1145
996be9ee 1146=cut
1147
11481;