only set use_namespaces=1 if naming is set for dynamic schemas
[dbsrgits/DBIx-Class-Schema-Loader.git] / lib / DBIx / Class / Schema / Loader / Base.pm
CommitLineData
996be9ee 1package DBIx::Class::Schema::Loader::Base;
2
3use strict;
4use warnings;
65e705c3 5use base qw/Class::Accessor::Grouped Class::C3::Componentised/;
942bd5e0 6use mro '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//;
ecf930e6 15use Lingua::EN::Inflect::Phrase qw//;
af31090c 16use File::Temp qw//;
17use Class::Unload;
8048320c 18use Class::Inspector ();
f170d55b 19use Scalar::Util 'looks_like_number';
b0d2b300 20use File::Slurp 'slurp';
0f21885a 21use DBIx::Class::Schema::Loader::Utils qw/split_name dumper_squashed eval_package_without_redefine_warnings class_path/;
ef8e9c69 22use DBIx::Class::Schema::Loader::Optional::Dependencies ();
906fa216 23use Try::Tiny;
ef8e9c69 24use DBIx::Class ();
2b74a06b 25use namespace::clean;
996be9ee 26
4295c4b4 27our $VERSION = '0.07010';
32f784fc 28
3d95f9ff 29__PACKAGE__->mk_group_ro_accessors('simple', qw/
996be9ee 30 schema
31 schema_class
32
33 exclude
34 constraint
35 additional_classes
36 additional_base_classes
37 left_base_classes
38 components
59cfa251 39 skip_relationships
0ca61324 40 skip_load_external
996be9ee 41 moniker_map
3fea497f 42 col_accessor_map
b639d969 43 custom_column_info
996be9ee 44 inflect_singular
45 inflect_plural
46 debug
47 dump_directory
d65cda9e 48 dump_overwrite
28b4691d 49 really_erase_my_files
f44ecc2f 50 resultset_namespace
51 default_resultset_class
9c9c2f2b 52 schema_base_class
53 result_base_class
d36c8734 54 result_roles
dcaf302a 55 use_moose
8de81918 56 overwrite_modifications
996be9ee 57
c8c27020 58 relationship_attrs
59
996be9ee 60 db_schema
61 _tables
62 classes
f53dcdf0 63 _upgrading_classes
996be9ee 64 monikers
106a976a 65 dynamic
a8d229ff 66 naming
9c703ffb 67 naming_set
42e785fa 68 datetime_timezone
69 datetime_locale
73099af4 70 config_file
71a6e88a 71 loader_class
69219349 72 qualify_objects
65e705c3 73/);
74
996be9ee 75
3d95f9ff 76__PACKAGE__->mk_group_accessors('simple', qw/
01012543 77 version_to_dump
1c95b304 78 schema_version_to_dump
f53dcdf0 79 _upgrading_from
f22644d7 80 _upgrading_from_load_classes
a4b94090 81 _downgrading_to_load_classes
540a8149 82 _rewriting_result_namespace
f22644d7 83 use_namespaces
540a8149 84 result_namespace
492dce8d 85 generate_pod
43b982ea 86 pod_comment_mode
87 pod_comment_spillover_length
bc1cb85e 88 preserve_case
15c4393b 89 col_collision_map
a7116285 90 rel_collision_map
1ad8e8c3 91 real_dump_directory
d36c8734 92 result_components_map
93 result_roles_map
57a9fc92 94 datetime_undef_if_invalid
26c54680 95 _result_class_methods
01012543 96/);
97
996be9ee 98=head1 NAME
99
100DBIx::Class::Schema::Loader::Base - Base DBIx::Class::Schema::Loader Implementation.
101
102=head1 SYNOPSIS
103
104See L<DBIx::Class::Schema::Loader>
105
106=head1 DESCRIPTION
107
108This is the base class for the storage-specific C<DBIx::Class::Schema::*>
109classes, and implements the common functionality between them.
110
111=head1 CONSTRUCTOR OPTIONS
112
113These constructor options are the base options for
29ddb54c 114L<DBIx::Class::Schema::Loader/loader_options>. Available constructor options are:
3953cbee 115
59cfa251 116=head2 skip_relationships
996be9ee 117
59cfa251 118Skip setting up relationships. The default is to attempt the loading
119of relationships.
996be9ee 120
0ca61324 121=head2 skip_load_external
122
123Skip loading of other classes in @INC. The default is to merge all other classes
124with the same name found in @INC into the schema file we are creating.
125
9a95164d 126=head2 naming
127
ecf930e6 128Static schemas (ones dumped to disk) will, by default, use the new-style
9a95164d 129relationship names and singularized Results, unless you're overwriting an
ecf930e6 130existing dump made by an older version of L<DBIx::Class::Schema::Loader>, in
131which case the backward compatible RelBuilder will be activated, and the
132appropriate monikerization used.
9a95164d 133
134Specifying
135
ecf930e6 136 naming => 'current'
9a95164d 137
138will disable the backward-compatible RelBuilder and use
139the new-style relationship names along with singularized Results, even when
140overwriting a dump made with an earlier version.
141
142The option also takes a hashref:
143
2a1ff2ee 144 naming => { relationships => 'v7', monikers => 'v7' }
a8d229ff 145
146The keys are:
147
148=over 4
149
150=item relationships
151
152How to name relationship accessors.
153
154=item monikers
155
156How to name Result classes.
157
f3a657ef 158=item column_accessors
159
160How to name column accessors in Result classes.
161
a8d229ff 162=back
9a95164d 163
164The values can be:
165
166=over 4
167
168=item current
169
ecf930e6 170Latest style, whatever that happens to be.
171
172=item v4
173
174Unsingularlized monikers, C<has_many> only relationships with no _id stripping.
9a95164d 175
176=item v5
177
ecf930e6 178Monikers singularized as whole words, C<might_have> relationships for FKs on
179C<UNIQUE> constraints, C<_id> stripping for belongs_to relationships.
9a95164d 180
ecf930e6 181Some of the C<_id> stripping edge cases in C<0.05003> have been reverted for
182the v5 RelBuilder.
183
184=item v6
9a95164d 185
19b7d71c 186All monikers and relationships are inflected using
187L<Lingua::EN::Inflect::Phrase>, and there is more aggressive C<_id> stripping
188from relationship names.
ecf930e6 189
190In general, there is very little difference between v5 and v6 schemas.
9a95164d 191
9990e58f 192=item v7
193
194This mode is identical to C<v6> mode, except that monikerization of CamelCase
195table names is also done correctly.
196
0c1d5b47 197CamelCase column names in case-preserving mode will also be handled correctly
198for relationship name inflection. See L</preserve_case>.
19b7d71c 199
f3a657ef 200In this mode, CamelCase L</column_accessors> are normalized based on case
201transition instead of just being lowercased, so C<FooId> becomes C<foo_id>.
202
19b7d71c 203If you don't have any CamelCase table or column names, you can upgrade without
204breaking any of your code.
9990e58f 205
9a95164d 206=back
207
208Dynamic schemas will always default to the 0.04XXX relationship names and won't
209singularize Results for backward compatibility, to activate the new RelBuilder
210and singularization put this in your C<Schema.pm> file:
211
212 __PACKAGE__->naming('current');
213
c9cf9b4d 214Or if you prefer to use 0.07XXX features but insure that nothing breaks in the
9a95164d 215next major version upgrade:
216
c9cf9b4d 217 __PACKAGE__->naming('v7');
9a95164d 218
492dce8d 219=head2 generate_pod
220
221By default POD will be generated for columns and relationships, using database
7f2de014 222metadata for the text if available and supported.
223
224Reading database metadata (e.g. C<COMMENT ON TABLE some_table ...>) is only
225supported for Postgres right now.
492dce8d 226
227Set this to C<0> to turn off all POD generation.
228
43b982ea 229=head2 pod_comment_mode
230
f7976fea 231Controls where table comments appear in the generated POD. Smaller table
232comments are appended to the C<NAME> section of the documentation, and larger
233ones are inserted into C<DESCRIPTION> instead. You can force a C<DESCRIPTION>
234section to be generated with the comment always, only use C<NAME>, or choose
235the length threshold at which the comment is forced into the description.
43b982ea 236
34896b5e 237=over 4
238
239=item name
240
241Use C<NAME> section only.
242
243=item description
244
245Force C<DESCRIPTION> always.
246
247=item auto
248
249Use C<DESCRIPTION> if length > L</pod_comment_spillover_length>, this is the
250default.
251
252=back
43b982ea 253
254=head2 pod_comment_spillover_length
255
256When pod_comment_mode is set to C<auto>, this is the length of the comment at
257which it will be forced into a separate description section.
258
259The default is C<60>
260
c8c27020 261=head2 relationship_attrs
262
263Hashref of attributes to pass to each generated relationship, listed
264by type. Also supports relationship type 'all', containing options to
265pass to all generated relationships. Attributes set for more specific
266relationship types override those set in 'all'.
267
268For example:
269
270 relationship_attrs => {
aa0867ee 271 belongs_to => { is_deferrable => 0 },
c8c27020 272 },
273
aa0867ee 274use this to turn off DEFERRABLE on your foreign key constraints.
c8c27020 275
996be9ee 276=head2 debug
277
278If set to true, each constructive L<DBIx::Class> statement the loader
279decides to execute will be C<warn>-ed before execution.
280
d65cda9e 281=head2 db_schema
282
283Set the name of the schema to load (schema in the sense that your database
284vendor means it). Does not currently support loading more than one schema
285name.
286
996be9ee 287=head2 constraint
288
289Only load tables matching regex. Best specified as a qr// regex.
290
291=head2 exclude
292
293Exclude tables matching regex. Best specified as a qr// regex.
294
295=head2 moniker_map
296
8f9d7ce5 297Overrides the default table name to moniker translation. Can be either
298a hashref of table keys and moniker values, or a coderef for a translator
996be9ee 299function taking a single scalar table name argument and returning
300a scalar moniker. If the hash entry does not exist, or the function
301returns a false value, the code falls back to default behavior
302for that table name.
303
9990e58f 304The default behavior is to split on case transition and non-alphanumeric
305boundaries, singularize the resulting phrase, then join the titlecased words
306together. Examples:
996be9ee 307
9990e58f 308 Table Name | Moniker Name
309 ---------------------------------
310 luser | Luser
311 luser_group | LuserGroup
312 luser-opts | LuserOpt
313 stations_visited | StationVisited
314 routeChange | RouteChange
996be9ee 315
3fea497f 316=head2 col_accessor_map
cfc5dce3 317
318Same as moniker_map, but for column accessor names. If a coderef is
319passed, the code is called with arguments of
320
321 the name of the column in the underlying database,
322 default accessor name that DBICSL would ordinarily give this column,
323 {
324 table_class => name of the DBIC class we are building,
325 table_moniker => calculated moniker for this table (after moniker_map if present),
326 table_name => name of the database table,
327 full_table_name => schema-qualified name of the database table (RDBMS specific),
328 schema_class => name of the schema class we are building,
329 column_info => hashref of column info (data_type, is_nullable, etc),
330 }
331
996be9ee 332=head2 inflect_plural
333
334Just like L</moniker_map> above (can be hash/code-ref, falls back to default
335if hash key does not exist or coderef returns false), but acts as a map
336for pluralizing relationship names. The default behavior is to utilize
a7a80921 337L<Lingua::EN::Inflect::Phrase/to_PL>.
996be9ee 338
339=head2 inflect_singular
340
341As L</inflect_plural> above, but for singularizing relationship names.
a7a80921 342Default behavior is to utilize L<Lingua::EN::Inflect::Phrase/to_S>.
996be9ee 343
9c9c2f2b 344=head2 schema_base_class
345
346Base class for your schema classes. Defaults to 'DBIx::Class::Schema'.
347
348=head2 result_base_class
349
2229729e 350Base class for your table classes (aka result classes). Defaults to
351'DBIx::Class::Core'.
9c9c2f2b 352
996be9ee 353=head2 additional_base_classes
354
355List of additional base classes all of your table classes will use.
356
357=head2 left_base_classes
358
359List of additional base classes all of your table classes will use
360that need to be leftmost.
361
362=head2 additional_classes
363
364List of additional classes which all of your table classes will use.
365
366=head2 components
367
368List of additional components to be loaded into all of your table
eccc52fe 369classes. A good example would be
370L<InflateColumn::DateTime|DBIx::Class::InflateColumn::DateTime>
996be9ee 371
d36c8734 372=head2 result_components_map
8d65c820 373
d36c8734 374A hashref of moniker keys and component values. Unlike C<components>, which
375loads the given components into every Result class, this option allows you to
376load certain components for specified Result classes. For example:
8d65c820 377
d36c8734 378 result_components_map => {
8d65c820 379 StationVisited => '+YourApp::Schema::Component::StationVisited',
380 RouteChange => [
381 '+YourApp::Schema::Component::RouteChange',
382 'InflateColumn::DateTime',
383 ],
384 }
385
386You may use this in conjunction with C<components>.
387
d36c8734 388=head2 result_roles
389
390List of L<Moose> roles to be applied to all of your Result classes.
391
392=head2 result_roles_map
393
394A hashref of moniker keys and role values. Unlike C<result_roles>, which
395applies the given roles to every Result class, this option allows you to apply
396certain roles for specified Result classes. For example:
397
398 result_roles_map => {
399 StationVisited => [
400 'YourApp::Role::Building',
401 'YourApp::Role::Destination',
402 ],
403 RouteChange => 'YourApp::Role::TripEvent',
404 }
405
406You may use this in conjunction with C<components>.
407
f44ecc2f 408=head2 use_namespaces
409
f22644d7 410This is now the default, to go back to L<DBIx::Class::Schema/load_classes> pass
411a C<0>.
412
f44ecc2f 413Generate result class names suitable for
414L<DBIx::Class::Schema/load_namespaces> and call that instead of
415L<DBIx::Class::Schema/load_classes>. When using this option you can also
416specify any of the options for C<load_namespaces> (i.e. C<result_namespace>,
417C<resultset_namespace>, C<default_resultset_class>), and they will be added
418to the call (and the generated result class names adjusted appropriately).
419
996be9ee 420=head2 dump_directory
421
996be9ee 422The value of this option is a perl libdir pathname. Within
423that directory this module will create a baseline manual
1ad8e8c3 424L<DBIx::Class::Schema> module set, based on what it creates at runtime.
996be9ee 425
426The created schema class will have the same classname as the one on
427which you are setting this option (and the ResultSource classes will be
7cab3ab7 428based on this name as well).
996be9ee 429
8f9d7ce5 430Normally you wouldn't hard-code this setting in your schema class, as it
996be9ee 431is meant for one-time manual usage.
432
433See L<DBIx::Class::Schema::Loader/dump_to_dir> for examples of the
434recommended way to access this functionality.
435
d65cda9e 436=head2 dump_overwrite
437
28b4691d 438Deprecated. See L</really_erase_my_files> below, which does *not* mean
439the same thing as the old C<dump_overwrite> setting from previous releases.
440
441=head2 really_erase_my_files
442
7cab3ab7 443Default false. If true, Loader will unconditionally delete any existing
444files before creating the new ones from scratch when dumping a schema to disk.
445
446The default behavior is instead to only replace the top portion of the
447file, up to and including the final stanza which contains
1a8fd949 448C<# DO NOT MODIFY THE FIRST PART OF THIS FILE>
7cab3ab7 449leaving any customizations you placed after that as they were.
450
28b4691d 451When C<really_erase_my_files> is not set, if the output file already exists,
7cab3ab7 452but the aforementioned final stanza is not found, or the checksum
453contained there does not match the generated contents, Loader will
454croak and not touch the file.
d65cda9e 455
28b4691d 456You should really be using version control on your schema classes (and all
457of the rest of your code for that matter). Don't blame me if a bug in this
458code wipes something out when it shouldn't have, you've been warned.
459
639a1367 460=head2 overwrite_modifications
461
462Default false. If false, when updating existing files, Loader will
463refuse to modify any Loader-generated code that has been modified
464since its last run (as determined by the checksum Loader put in its
465comment lines).
466
467If true, Loader will discard any manual modifications that have been
468made to Loader-generated code.
469
470Again, you should be using version control on your schema classes. Be
471careful with this option.
472
3a368709 473=head2 custom_column_info
474
d67d058e 475Hook for adding extra attributes to the
476L<column_info|DBIx::Class::ResultSource/column_info> for a column.
477
478Must be a coderef that returns a hashref with the extra attributes.
479
480Receives the table name, column name and column_info.
481
482For example:
483
484 custom_column_info => sub {
485 my ($table_name, $column_name, $column_info) = @_;
486
487 if ($column_name eq 'dog' && $column_info->{default_value} eq 'snoopy') {
488 return { is_snoopy => 1 };
489 }
490 },
3a368709 491
d67d058e 492This attribute can also be used to set C<inflate_datetime> on a non-datetime
493column so it also receives the L</datetime_timezone> and/or L</datetime_locale>.
3a368709 494
42e785fa 495=head2 datetime_timezone
496
d67d058e 497Sets the timezone attribute for L<DBIx::Class::InflateColumn::DateTime> for all
498columns with the DATE/DATETIME/TIMESTAMP data_types.
42e785fa 499
500=head2 datetime_locale
501
d67d058e 502Sets the locale attribute for L<DBIx::Class::InflateColumn::DateTime> for all
503columns with the DATE/DATETIME/TIMESTAMP data_types.
42e785fa 504
57a9fc92 505=head2 datetime_undef_if_invalid
506
507Pass a C<0> for this option when using MySQL if you B<DON'T> want C<<
508datetime_undef_if_invalid => 1 >> in your column info for DATE, DATETIME and
509TIMESTAMP columns.
510
511The default is recommended to deal with data such as C<00/00/00> which
512sometimes ends up in such columns in MySQL.
513
7ffafa37 514=head2 config_file
73099af4 515
516File in Perl format, which should return a HASH reference, from which to read
517loader options.
518
7ffafa37 519=head2 preserve_case
bc1cb85e 520
521Usually column names are lowercased, to make them easier to work with in
522L<DBIx::Class>. This option lets you turn this behavior off, if the driver
523supports it.
524
525Drivers for case sensitive databases like Sybase ASE or MSSQL with a
526case-sensitive collation will turn this option on unconditionally.
527
528Currently the drivers for SQLite, mysql, MSSQL and Firebird/InterBase support
529setting this option.
530
7ffafa37 531=head2 qualify_objects
69219349 532
533Set to true to prepend the L</db_schema> to table names for C<<
534__PACKAGE__->table >> calls, and to some other things like Oracle sequences.
535
7d0ea6b9 536=head2 use_moose
537
538Creates Schema and Result classes that use L<Moose>, L<MooseX::NonMoose> and
1336ac63 539L<namespace::autoclean>. The default content after the md5 sum also makes the
540classes immutable.
7d0ea6b9 541
542It is safe to upgrade your existing Schema to this option.
543
15c4393b 544=head2 col_collision_map
545
546This option controls how accessors for column names which collide with perl
547methods are named. See L</COLUMN ACCESSOR COLLISIONS> for more information.
548
dcc51168 549This option takes either a single L<sprintf|perlfunc/sprintf> format or a hashref of
15c4393b 550strings which are compiled to regular expressions that map to
dcc51168 551L<sprintf|perlfunc/sprintf> formats.
15c4393b 552
553Examples:
554
555 col_collision_map => 'column_%s'
556
557 col_collision_map => { '(.*)' => 'column_%s' }
558
559 col_collision_map => { '(foo).*(bar)' => 'column_%s_%s' }
560
a7116285 561=head2 rel_collision_map
562
563Works just like L</col_collision_map>, but for relationship names/accessors
564rather than column names/accessors.
565
566The default is to just append C<_rel> to the relationship name, see
567L</RELATIONSHIP NAME COLLISIONS>.
568
996be9ee 569=head1 METHODS
570
571None of these methods are intended for direct invocation by regular
d67d058e 572users of L<DBIx::Class::Schema::Loader>. Some are proxied via
573L<DBIx::Class::Schema::Loader>.
996be9ee 574
575=cut
576
9990e58f 577my $CURRENT_V = 'v7';
8048320c 578
c5df7397 579my @CLASS_ARGS = qw(
8048320c 580 schema_base_class result_base_class additional_base_classes
d36c8734 581 left_base_classes additional_classes components result_roles
8048320c 582);
66afce69 583
996be9ee 584# ensure that a peice of object data is a valid arrayref, creating
585# an empty one or encapsulating whatever's there.
586sub _ensure_arrayref {
587 my $self = shift;
588
589 foreach (@_) {
590 $self->{$_} ||= [];
591 $self->{$_} = [ $self->{$_} ]
592 unless ref $self->{$_} eq 'ARRAY';
593 }
594}
595
596=head2 new
597
598Constructor for L<DBIx::Class::Schema::Loader::Base>, used internally
599by L<DBIx::Class::Schema::Loader>.
600
601=cut
602
603sub new {
604 my ( $class, %args ) = @_;
605
3fea497f 606 if (exists $args{column_accessor_map}) {
607 $args{col_accessor_map} = delete $args{column_accessor_map};
608 }
609
996be9ee 610 my $self = { %args };
611
8de81918 612 # don't lose undef options
613 for (values %$self) {
614 $_ = 0 unless defined $_;
615 }
616
996be9ee 617 bless $self => $class;
618
73099af4 619 if (my $config_file = $self->config_file) {
620 my $config_opts = do $config_file;
621
622 croak "Error reading config from $config_file: $@" if $@;
623
624 croak "Config file $config_file must be a hashref" unless ref($config_opts) eq 'HASH';
625
626 while (my ($k, $v) = each %$config_opts) {
627 $self->{$k} = $v unless exists $self->{$k};
628 }
629 }
630
d36c8734 631 $self->result_components_map($self->{result_component_map})
632 if defined $self->{result_component_map};
633
634 $self->result_roles_map($self->{result_role_map})
635 if defined $self->{result_role_map};
636
637 croak "the result_roles and result_roles_map options may only be used in conjunction with use_moose=1"
638 if ((not defined $self->use_moose) || (not $self->use_moose))
639 && ((defined $self->result_roles) || (defined $self->result_roles_map));
640
996be9ee 641 $self->_ensure_arrayref(qw/additional_classes
642 additional_base_classes
643 left_base_classes
644 components
d36c8734 645 result_roles
996be9ee 646 /);
647
8048320c 648 $self->_validate_class_args;
649
d36c8734 650 croak "result_components_map must be a hash"
651 if defined $self->result_components_map
652 && ref $self->result_components_map ne 'HASH';
653
654 if ($self->result_components_map) {
655 my %rc_map = %{ $self->result_components_map };
8d65c820 656 foreach my $moniker (keys %rc_map) {
657 $rc_map{$moniker} = [ $rc_map{$moniker} ] unless ref $rc_map{$moniker};
658 }
d36c8734 659 $self->result_components_map(\%rc_map);
8d65c820 660 }
95b0a8b9 661 else {
d36c8734 662 $self->result_components_map({});
95b0a8b9 663 }
d36c8734 664 $self->_validate_result_components_map;
665
666 croak "result_roles_map must be a hash"
667 if defined $self->result_roles_map
668 && ref $self->result_roles_map ne 'HASH';
669
670 if ($self->result_roles_map) {
671 my %rr_map = %{ $self->result_roles_map };
672 foreach my $moniker (keys %rr_map) {
673 $rr_map{$moniker} = [ $rr_map{$moniker} ] unless ref $rr_map{$moniker};
674 }
675 $self->result_roles_map(\%rr_map);
676 } else {
677 $self->result_roles_map({});
678 }
679 $self->_validate_result_roles_map;
8d65c820 680
c9cf9b4d 681 if ($self->use_moose) {
ef8e9c69 682 if (not DBIx::Class::Schema::Loader::Optional::Dependencies->req_ok_for('use_moose')) {
53e721bc 683 die sprintf "You must install the following CPAN modules to enable the use_moose option: %s.\n",
ef8e9c69 684 DBIx::Class::Schema::Loader::Optional::Dependencies->req_missing_for('use_moose');
c9cf9b4d 685 }
686 }
687
996be9ee 688 $self->{monikers} = {};
689 $self->{classes} = {};
f53dcdf0 690 $self->{_upgrading_classes} = {};
996be9ee 691
996be9ee 692 $self->{schema_class} ||= ( ref $self->{schema} || $self->{schema} );
693 $self->{schema} ||= $self->{schema_class};
694
28b4691d 695 croak "dump_overwrite is deprecated. Please read the"
696 . " DBIx::Class::Schema::Loader::Base documentation"
697 if $self->{dump_overwrite};
698
af31090c 699 $self->{dynamic} = ! $self->{dump_directory};
79193756 700 $self->{temp_directory} ||= File::Temp::tempdir( 'dbicXXXX',
af31090c 701 TMPDIR => 1,
702 CLEANUP => 1,
703 );
704
79193756 705 $self->{dump_directory} ||= $self->{temp_directory};
706
1ad8e8c3 707 $self->real_dump_directory($self->{dump_directory});
708
01012543 709 $self->version_to_dump($DBIx::Class::Schema::Loader::VERSION);
1c95b304 710 $self->schema_version_to_dump($DBIx::Class::Schema::Loader::VERSION);
01012543 711
9c703ffb 712 if (not defined $self->naming) {
713 $self->naming_set(0);
714 }
715 else {
716 $self->naming_set(1);
717 }
718
66afce69 719 if ((not ref $self->naming) && defined $self->naming) {
9cc8e7e1 720 my $naming_ver = $self->naming;
a8d229ff 721 $self->{naming} = {
722 relationships => $naming_ver,
723 monikers => $naming_ver,
f3a657ef 724 column_accessors => $naming_ver,
a8d229ff 725 };
726 }
727
66afce69 728 if ($self->naming) {
729 for (values %{ $self->naming }) {
c5df7397 730 $_ = $CURRENT_V if $_ eq 'current';
66afce69 731 }
732 }
733 $self->{naming} ||= {};
734
d67d058e 735 if ($self->custom_column_info && ref $self->custom_column_info ne 'CODE') {
736 croak 'custom_column_info must be a CODE ref';
737 }
738
7824616e 739 $self->_check_back_compat;
9c465d2c 740
f22644d7 741 $self->use_namespaces(1) unless defined $self->use_namespaces;
492dce8d 742 $self->generate_pod(1) unless defined $self->generate_pod;
43b982ea 743 $self->pod_comment_mode('auto') unless defined $self->pod_comment_mode;
744 $self->pod_comment_spillover_length(60) unless defined $self->pod_comment_spillover_length;
f22644d7 745
15c4393b 746 if (my $col_collision_map = $self->col_collision_map) {
747 if (my $reftype = ref $col_collision_map) {
748 if ($reftype ne 'HASH') {
749 croak "Invalid type $reftype for option 'col_collision_map'";
750 }
751 }
752 else {
753 $self->col_collision_map({ '(.*)' => $col_collision_map });
754 }
755 }
756
7824616e 757 $self;
758}
af31090c 759
7824616e 760sub _check_back_compat {
761 my ($self) = @_;
e8ad6491 762
a8d229ff 763# dynamic schemas will always be in 0.04006 mode, unless overridden
106a976a 764 if ($self->dynamic) {
fb3bb595 765# just in case, though no one is likely to dump a dynamic schema
1c95b304 766 $self->schema_version_to_dump('0.04006');
a8d229ff 767
66afce69 768 if (not %{ $self->naming }) {
769 warn <<EOF unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
770
771Dynamic schema detected, will run in 0.04006 mode.
772
773Set the 'naming' attribute or the SCHEMA_LOADER_BACKCOMPAT environment variable
774to disable this warning.
a0e0a56a 775
776See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 for more
777details.
66afce69 778EOF
779 }
f53dcdf0 780 else {
781 $self->_upgrading_from('v4');
782 }
66afce69 783
9c703ffb 784 if ((not defined $self->use_namespaces) && (not $self->naming_set)) {
0f21885a 785 $self->use_namespaces(1);
786 }
787
9c703ffb 788 $self->naming->{relationships} ||= 'v4';
789 $self->naming->{monikers} ||= 'v4';
790
805dbe0a 791 if ($self->use_namespaces) {
792 $self->_upgrading_from_load_classes(1);
793 }
794 else {
795 $self->use_namespaces(0);
796 }
f22644d7 797
01012543 798 return;
799 }
800
801# otherwise check if we need backcompat mode for a static schema
7824616e 802 my $filename = $self->_get_dump_filename($self->schema_class);
803 return unless -e $filename;
804
8de81918 805 my ($old_gen, $old_md5, $old_ver, $old_ts, $old_custom) =
806 $self->_parse_generated_file($filename);
7824616e 807
8de81918 808 return unless $old_ver;
809
810 # determine if the existing schema was dumped with use_moose => 1
811 if (! defined $self->use_moose) {
53e721bc 812 $self->{use_moose} = 1 if $old_gen =~ /^ (?!\s*\#) use \s+ Moose/xm;
8de81918 813 }
f22644d7 814
8de81918 815 my $load_classes = ($old_gen =~ /^__PACKAGE__->load_classes;/m) ? 1 : 0;
816 my $result_namespace = do { ($old_gen =~ /result_namespace => '([^']+)'/) ? $1 : '' };
805dbe0a 817
8de81918 818 if ($load_classes && (not defined $self->use_namespaces)) {
819 warn <<"EOF" unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
805dbe0a 820
a1a91c42 821'load_classes;' static schema detected, turning off 'use_namespaces'.
805dbe0a 822
823Set the 'use_namespaces' attribute or the SCHEMA_LOADER_BACKCOMPAT environment
824variable to disable this warning.
825
826See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 for more
827details.
828EOF
8de81918 829 $self->use_namespaces(0);
830 }
831 elsif ($load_classes && $self->use_namespaces) {
832 $self->_upgrading_from_load_classes(1);
833 }
834 elsif ((not $load_classes) && defined $self->use_namespaces && ! $self->use_namespaces) {
835 $self->_downgrading_to_load_classes(
836 $result_namespace || 'Result'
837 );
838 }
839 elsif ((not defined $self->use_namespaces) || $self->use_namespaces) {
840 if (not $self->result_namespace) {
841 $self->result_namespace($result_namespace || 'Result');
842 }
843 elsif ($result_namespace ne $self->result_namespace) {
844 $self->_rewriting_result_namespace(
845 $result_namespace || 'Result'
846 );
847 }
848 }
a8d229ff 849
8de81918 850 # XXX when we go past .0 this will need fixing
851 my ($v) = $old_ver =~ /([1-9])/;
852 $v = "v$v";
a8d229ff 853
8de81918 854 return if ($v eq $CURRENT_V || $old_ver =~ /^0\.\d\d999/);
a0e0a56a 855
8de81918 856 if (not %{ $self->naming }) {
857 warn <<"EOF" unless $ENV{SCHEMA_LOADER_BACKCOMPAT};
a0e0a56a 858
8de81918 859Version $old_ver static schema detected, turning on backcompat mode.
a0e0a56a 860
861Set the 'naming' attribute or the SCHEMA_LOADER_BACKCOMPAT environment variable
862to disable this warning.
863
9990e58f 864See: 'naming' in perldoc DBIx::Class::Schema::Loader::Base .
865
2a8e93e9 866See perldoc DBIx::Class::Schema::Loader::Manual::UpgradingFromV4 if upgrading
867from version 0.04006.
a0e0a56a 868EOF
a8d229ff 869
8de81918 870 $self->naming->{relationships} ||= $v;
871 $self->naming->{monikers} ||= $v;
872 $self->naming->{column_accessors} ||= $v;
a0e0a56a 873
8de81918 874 $self->schema_version_to_dump($old_ver);
875 }
876 else {
877 $self->_upgrading_from($v);
7824616e 878 }
996be9ee 879}
880
8048320c 881sub _validate_class_args {
882 my $self = shift;
8de81918 883
c5df7397 884 foreach my $k (@CLASS_ARGS) {
8048320c 885 next unless $self->$k;
886
887 my @classes = ref $self->$k eq 'ARRAY' ? @{ $self->$k } : $self->$k;
8d65c820 888 $self->_validate_classes($k, \@classes);
889 }
890}
8048320c 891
d36c8734 892sub _validate_result_components_map {
8d65c820 893 my $self = shift;
894
d36c8734 895 foreach my $classes (values %{ $self->result_components_map }) {
896 $self->_validate_classes('result_components_map', $classes);
897 }
898}
899
900sub _validate_result_roles_map {
901 my $self = shift;
8d65c820 902
d36c8734 903 foreach my $classes (values %{ $self->result_roles_map }) {
904 $self->_validate_classes('result_roles_map', $classes);
8d65c820 905 }
906}
907
908sub _validate_classes {
909 my $self = shift;
910 my $key = shift;
911 my $classes = shift;
912
d36c8734 913 # make a copy to not destroy original
914 my @classes = @$classes;
915
916 foreach my $c (@classes) {
8d65c820 917 # components default to being under the DBIx::Class namespace unless they
918 # are preceeded with a '+'
919 if ( $key =~ m/component/ && $c !~ s/^\+// ) {
920 $c = 'DBIx::Class::' . $c;
921 }
922
923 # 1 == installed, 0 == not installed, undef == invalid classname
924 my $installed = Class::Inspector->installed($c);
925 if ( defined($installed) ) {
926 if ( $installed == 0 ) {
927 croak qq/$c, as specified in the loader option "$key", is not installed/;
8048320c 928 }
8d65c820 929 } else {
930 croak qq/$c, as specified in the loader option "$key", is an invalid class name/;
8048320c 931 }
932 }
933}
934
8d65c820 935
419a2eeb 936sub _find_file_in_inc {
937 my ($self, $file) = @_;
938
939 foreach my $prefix (@INC) {
af31090c 940 my $fullpath = File::Spec->catfile($prefix, $file);
941 return $fullpath if -f $fullpath
281d0f3e 942 # abs_path throws on Windows for nonexistant files
1ad8e8c3 943 and (try { Cwd::abs_path($fullpath) }) ne
944 ((try { Cwd::abs_path(File::Spec->catfile($self->dump_directory, $file)) }) || '');
419a2eeb 945 }
946
947 return;
948}
949
fb3bb595 950sub _find_class_in_inc {
951 my ($self, $class) = @_;
952
0f21885a 953 return $self->_find_file_in_inc(class_path($class));
fb3bb595 954}
955
a4b94090 956sub _rewriting {
957 my $self = shift;
958
959 return $self->_upgrading_from
960 || $self->_upgrading_from_load_classes
540a8149 961 || $self->_downgrading_to_load_classes
962 || $self->_rewriting_result_namespace
963 ;
a4b94090 964}
965
b24cb177 966sub _rewrite_old_classnames {
967 my ($self, $code) = @_;
968
a4b94090 969 return $code unless $self->_rewriting;
b24cb177 970
971 my %old_classes = reverse %{ $self->_upgrading_classes };
972
973 my $re = join '|', keys %old_classes;
974 $re = qr/\b($re)\b/;
975
68d49e50 976 $code =~ s/$re/$old_classes{$1} || $1/eg;
b24cb177 977
978 return $code;
979}
980
fb3bb595 981sub _load_external {
982 my ($self, $class) = @_;
983
0ca61324 984 return if $self->{skip_load_external};
985
ffc705f3 986 # so that we don't load our own classes, under any circumstances
987 local *INC = [ grep $_ ne $self->dump_directory, @INC ];
988
fb3bb595 989 my $real_inc_path = $self->_find_class_in_inc($class);
f96ef30f 990
ffc705f3 991 my $old_class = $self->_upgrading_classes->{$class}
a4b94090 992 if $self->_rewriting;
ffc705f3 993
994 my $old_real_inc_path = $self->_find_class_in_inc($old_class)
995 if $old_class && $old_class ne $class;
996
997 return unless $real_inc_path || $old_real_inc_path;
998
999 if ($real_inc_path) {
1000 # If we make it to here, we loaded an external definition
1001 warn qq/# Loaded external class definition for '$class'\n/
1002 if $self->debug;
1003
0dd4099e 1004 my $code = $self->_rewrite_old_classnames(scalar slurp $real_inc_path);
ffc705f3 1005
1006 if ($self->dynamic) { # load the class too
0f21885a 1007 eval_package_without_redefine_warnings($class, $code);
ffc705f3 1008 }
b24cb177 1009
1010 $self->_ext_stmt($class,
1011 qq|# These lines were loaded from '$real_inc_path' found in \@INC.\n|
1012 .qq|# They are now part of the custom portion of this file\n|
1013 .qq|# for you to hand-edit. If you do not either delete\n|
1014 .qq|# this section or remove that file from \@INC, this section\n|
1015 .qq|# will be repeated redundantly when you re-create this\n|
e770e9ce 1016 .qq|# file again via Loader! See skip_load_external to disable\n|
1017 .qq|# this feature.\n|
b24cb177 1018 );
1019 chomp $code;
1020 $self->_ext_stmt($class, $code);
1021 $self->_ext_stmt($class,
1022 qq|# End of lines loaded from '$real_inc_path' |
1023 );
996be9ee 1024 }
106a976a 1025
ffc705f3 1026 if ($old_real_inc_path) {
b511f36e 1027 my $code = slurp $old_real_inc_path;
1028
ffc705f3 1029 $self->_ext_stmt($class, <<"EOF");
1030
30a4c064 1031# These lines were loaded from '$old_real_inc_path',
b08ea624 1032# based on the Result class name that would have been created by an older
30a4c064 1033# version of the Loader. For a static schema, this happens only once during
e770e9ce 1034# upgrade. See skip_load_external to disable this feature.
ffc705f3 1035EOF
b24cb177 1036
b24cb177 1037 $code = $self->_rewrite_old_classnames($code);
1038
ffc705f3 1039 if ($self->dynamic) {
1040 warn <<"EOF";
1041
1042Detected external content in '$old_real_inc_path', a class name that would have
b08ea624 1043been used by an older version of the Loader.
ffc705f3 1044
1045* PLEASE RENAME THIS CLASS: from '$old_class' to '$class', as that is the
1046new name of the Result.
1047EOF
0f21885a 1048 eval_package_without_redefine_warnings($class, $code);
ffc705f3 1049 }
1050
b24cb177 1051 chomp $code;
1052 $self->_ext_stmt($class, $code);
ffc705f3 1053 $self->_ext_stmt($class,
1054 qq|# End of lines loaded from '$old_real_inc_path' |
1055 );
9e8033c1 1056 }
996be9ee 1057}
1058
1059=head2 load
1060
1061Does the actual schema-construction work.
1062
1063=cut
1064
1065sub load {
1066 my $self = shift;
1067
bfb43060 1068 $self->_load_tables(
1069 $self->_tables_list({ constraint => $self->constraint, exclude => $self->exclude })
1070 );
b97c2c1e 1071}
1072
1073=head2 rescan
1074
a60b5b8d 1075Arguments: schema
1076
b511f36e 1077Rescan the database for changes. Returns a list of the newly added table
1078monikers.
a60b5b8d 1079
b511f36e 1080The schema argument should be the schema class or object to be affected. It
1081should probably be derived from the original schema_class used during L</load>.
b97c2c1e 1082
1083=cut
1084
1085sub rescan {
a60b5b8d 1086 my ($self, $schema) = @_;
1087
1088 $self->{schema} = $schema;
7824616e 1089 $self->_relbuilder->{schema} = $schema;
b97c2c1e 1090
1091 my @created;
bfb43060 1092 my @current = $self->_tables_list({ constraint => $self->constraint, exclude => $self->exclude });
0c1d5b47 1093
bfb43060 1094 foreach my $table (@current) {
b97c2c1e 1095 if(!exists $self->{_tables}->{$table}) {
1096 push(@created, $table);
1097 }
1098 }
1099
0c1d5b47 1100 my %current;
1101 @current{@current} = ();
1102 foreach my $table (keys %{ $self->{_tables} }) {
1103 if (not exists $current{$table}) {
1104 $self->_unregister_source_for_table($table);
1105 }
1106 }
1107
b511f36e 1108 delete $self->{_dump_storage};
1109 delete $self->{_relations_started};
1110
1111 my $loaded = $self->_load_tables(@current);
a60b5b8d 1112
b511f36e 1113 return map { $self->monikers->{$_} } @created;
b97c2c1e 1114}
1115
7824616e 1116sub _relbuilder {
1117 my ($self) = @_;
3fed44ca 1118
1119 return if $self->{skip_relationships};
1120
ef372cf4 1121 return $self->{relbuilder} ||= do {
1122
1123 no warnings 'uninitialized';
1124 my $relbuilder_suff =
1125 {qw{
1126 v4 ::Compat::v0_040
1127 v5 ::Compat::v0_05
1128 v6 ::Compat::v0_06
1129 }}
1130 ->{ $self->naming->{relationships}};
1131
1132 my $relbuilder_class = 'DBIx::Class::Schema::Loader::RelBuilder'.$relbuilder_suff;
7eff9ea3 1133 $self->ensure_class_loaded($relbuilder_class);
ef372cf4 1134 $relbuilder_class->new( $self );
a8d229ff 1135
ef372cf4 1136 };
7824616e 1137}
1138
b97c2c1e 1139sub _load_tables {
1140 my ($self, @tables) = @_;
1141
b97c2c1e 1142 # Save the new tables to the tables list
a60b5b8d 1143 foreach (@tables) {
1144 $self->{_tables}->{$_} = 1;
1145 }
f96ef30f 1146
af31090c 1147 $self->_make_src_class($_) for @tables;
27305cc1 1148
27305cc1 1149 # sanity-check for moniker clashes
1150 my $inverse_moniker_idx;
1151 for (keys %{$self->monikers}) {
1152 push @{$inverse_moniker_idx->{$self->monikers->{$_}}}, $_;
1153 }
1154
1155 my @clashes;
1156 for (keys %$inverse_moniker_idx) {
1157 my $tables = $inverse_moniker_idx->{$_};
1158 if (@$tables > 1) {
1159 push @clashes, sprintf ("tables %s reduced to the same source moniker '%s'",
1160 join (', ', map { "'$_'" } @$tables),
1161 $_,
1162 );
1163 }
1164 }
1165
1166 if (@clashes) {
1167 die 'Unable to load schema - chosen moniker/class naming style results in moniker clashes. '
1168 . 'Either change the naming style, or supply an explicit moniker_map: '
1169 . join ('; ', @clashes)
1170 . "\n"
1171 ;
1172 }
1173
1174
f96ef30f 1175 $self->_setup_src_meta($_) for @tables;
1176
e8ad6491 1177 if(!$self->skip_relationships) {
181cc907 1178 # The relationship loader needs a working schema
af31090c 1179 $self->{quiet} = 1;
79193756 1180 local $self->{dump_directory} = $self->{temp_directory};
106a976a 1181 $self->_reload_classes(\@tables);
e8ad6491 1182 $self->_load_relationships($_) for @tables;
8c70d2c7 1183 $self->_relbuilder->cleanup;
af31090c 1184 $self->{quiet} = 0;
79193756 1185
1186 # Remove that temp dir from INC so it doesn't get reloaded
ffc705f3 1187 @INC = grep $_ ne $self->dump_directory, @INC;
e8ad6491 1188 }
1189
f96ef30f 1190 $self->_load_external($_)
75451704 1191 for map { $self->classes->{$_} } @tables;
f96ef30f 1192
106a976a 1193 # Reload without unloading first to preserve any symbols from external
1194 # packages.
1ad8e8c3 1195 $self->_reload_classes(\@tables, { unload => 0 });
996be9ee 1196
5223f24a 1197 # Drop temporary cache
1198 delete $self->{_cache};
1199
c39e3507 1200 return \@tables;
996be9ee 1201}
1202
af31090c 1203sub _reload_classes {
1ad8e8c3 1204 my ($self, $tables, $opts) = @_;
106a976a 1205
1206 my @tables = @$tables;
1ad8e8c3 1207
1208 my $unload = $opts->{unload};
106a976a 1209 $unload = 1 unless defined $unload;
181cc907 1210
4daef04f 1211 # so that we don't repeat custom sections
1212 @INC = grep $_ ne $self->dump_directory, @INC;
1213
181cc907 1214 $self->_dump_to_dir(map { $self->classes->{$_} } @tables);
e9b8719e 1215
1216 unshift @INC, $self->dump_directory;
af31090c 1217
706ef173 1218 my @to_register;
1219 my %have_source = map { $_ => $self->schema->source($_) }
1220 $self->schema->sources;
1221
181cc907 1222 for my $table (@tables) {
1223 my $moniker = $self->monikers->{$table};
1224 my $class = $self->classes->{$table};
0ae6b65d 1225
1226 {
1227 no warnings 'redefine';
942bd5e0 1228 local *Class::C3::reinitialize = sub {}; # to speed things up, reinitialized below
0ae6b65d 1229 use warnings;
1230
01f93238 1231 if (my $mc = $self->_moose_metaclass($class)) {
1232 $mc->make_mutable;
c9cf9b4d 1233 }
106a976a 1234 Class::Unload->unload($class) if $unload;
706ef173 1235 my ($source, $resultset_class);
1236 if (
1237 ($source = $have_source{$moniker})
1238 && ($resultset_class = $source->resultset_class)
1239 && ($resultset_class ne 'DBIx::Class::ResultSet')
1240 ) {
1241 my $has_file = Class::Inspector->loaded_filename($resultset_class);
01f93238 1242 if (my $mc = $self->_moose_metaclass($resultset_class)) {
1243 $mc->make_mutable;
c9cf9b4d 1244 }
106a976a 1245 Class::Unload->unload($resultset_class) if $unload;
1246 $self->_reload_class($resultset_class) if $has_file;
0ae6b65d 1247 }
106a976a 1248 $self->_reload_class($class);
af31090c 1249 }
706ef173 1250 push @to_register, [$moniker, $class];
1251 }
af31090c 1252
706ef173 1253 Class::C3->reinitialize;
1254 for (@to_register) {
1255 $self->schema->register_class(@$_);
af31090c 1256 }
1257}
1258
01f93238 1259sub _moose_metaclass {
1260 return undef unless $INC{'Class/MOP.pm'}; # if CMOP is not loaded the class could not have loaded in the 1st place
1261
0dd4099e 1262 my $class = $_[1];
1263
1264 my $mc = try { Class::MOP::class_of($class) }
01f93238 1265 or return undef;
1266
1267 return $mc->isa('Moose::Meta::Class') ? $mc : undef;
1268}
1269
106a976a 1270# We use this instead of ensure_class_loaded when there are package symbols we
1271# want to preserve.
1272sub _reload_class {
1273 my ($self, $class) = @_;
1274
0f21885a 1275 delete $INC{ +class_path($class) };
f53dcdf0 1276
1ad8e8c3 1277 try {
0f21885a 1278 eval_package_without_redefine_warnings ($class, "require $class");
1ad8e8c3 1279 }
1280 catch {
61d1cca1 1281 my $source = slurp $self->_get_dump_filename($class);
1282 die "Failed to reload class $class: $_.\n\nCLASS SOURCE:\n\n$source";
f53dcdf0 1283 };
106a976a 1284}
1285
996be9ee 1286sub _get_dump_filename {
1287 my ($self, $class) = (@_);
1288
1289 $class =~ s{::}{/}g;
1290 return $self->dump_directory . q{/} . $class . q{.pm};
1291}
1292
1ad8e8c3 1293=head2 get_dump_filename
1294
1295Arguments: class
1296
1297Returns the full path to the file for a class that the class has been or will
1298be dumped to. This is a file in a temp dir for a dynamic schema.
1299
1300=cut
1301
1302sub get_dump_filename {
1303 my ($self, $class) = (@_);
1304
1305 local $self->{dump_directory} = $self->real_dump_directory;
1306
1307 return $self->_get_dump_filename($class);
1308}
1309
996be9ee 1310sub _ensure_dump_subdirs {
1311 my ($self, $class) = (@_);
1312
1313 my @name_parts = split(/::/, $class);
dd03ee1a 1314 pop @name_parts; # we don't care about the very last element,
1315 # which is a filename
1316
996be9ee 1317 my $dir = $self->dump_directory;
7cab3ab7 1318 while (1) {
1319 if(!-d $dir) {
25328cc4 1320 mkdir($dir) or croak "mkdir('$dir') failed: $!";
996be9ee 1321 }
7cab3ab7 1322 last if !@name_parts;
1323 $dir = File::Spec->catdir($dir, shift @name_parts);
996be9ee 1324 }
1325}
1326
1327sub _dump_to_dir {
af31090c 1328 my ($self, @classes) = @_;
996be9ee 1329
fc2b71fd 1330 my $schema_class = $self->schema_class;
9c9c2f2b 1331 my $schema_base_class = $self->schema_base_class || 'DBIx::Class::Schema';
996be9ee 1332
e9b8719e 1333 my $target_dir = $self->dump_directory;
af31090c 1334 warn "Dumping manual schema for $schema_class to directory $target_dir ...\n"
1335 unless $self->{dynamic} or $self->{quiet};
996be9ee 1336
7cab3ab7 1337 my $schema_text =
1338 qq|package $schema_class;\n\n|
b4dcbcc5 1339 . qq|# Created by DBIx::Class::Schema::Loader\n|
1ad8e8c3 1340 . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|;
1341
dcaf302a 1342 if ($self->use_moose) {
49643e1d 1343 $schema_text.= qq|use Moose;\nuse namespace::autoclean;\nextends '$schema_base_class';\n\n|;
dcaf302a 1344 }
1345 else {
1ad8e8c3 1346 $schema_text .= qq|use strict;\nuse warnings;\n\nuse base '$schema_base_class';\n\n|;
dcaf302a 1347 }
f44ecc2f 1348
f44ecc2f 1349 if ($self->use_namespaces) {
1350 $schema_text .= qq|__PACKAGE__->load_namespaces|;
1351 my $namespace_options;
2a8e93e9 1352
1353 my @attr = qw/resultset_namespace default_resultset_class/;
1354
1355 unshift @attr, 'result_namespace' unless (not $self->result_namespace) || $self->result_namespace eq 'Result';
1356
1357 for my $attr (@attr) {
f44ecc2f 1358 if ($self->$attr) {
1359 $namespace_options .= qq| $attr => '| . $self->$attr . qq|',\n|
1360 }
1361 }
1362 $schema_text .= qq|(\n$namespace_options)| if $namespace_options;
1363 $schema_text .= qq|;\n|;
1364 }
1365 else {
1366 $schema_text .= qq|__PACKAGE__->load_classes;\n|;
f44ecc2f 1367 }
996be9ee 1368
1c95b304 1369 {
1370 local $self->{version_to_dump} = $self->schema_version_to_dump;
68d49e50 1371 $self->_write_classfile($schema_class, $schema_text, 1);
1c95b304 1372 }
996be9ee 1373
2229729e 1374 my $result_base_class = $self->result_base_class || 'DBIx::Class::Core';
9c9c2f2b 1375
af31090c 1376 foreach my $src_class (@classes) {
7cab3ab7 1377 my $src_text =
1378 qq|package $src_class;\n\n|
b4dcbcc5 1379 . qq|# Created by DBIx::Class::Schema::Loader\n|
1380 . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|
dcaf302a 1381 . qq|use strict;\nuse warnings;\n\n|;
1382 if ($self->use_moose) {
6c2b21a5 1383 $src_text.= qq|use Moose;\nuse MooseX::NonMoose;\nuse namespace::autoclean;|;
1384
1385 # these options 'use base' which is compile time
2b74a06b 1386 if (@{ $self->left_base_classes } || @{ $self->additional_base_classes }) {
6c2b21a5 1387 $src_text .= qq|\nBEGIN { extends '$result_base_class' }\n\n|;
1388 }
1389 else {
1390 $src_text .= qq|\nextends '$result_base_class';\n\n|;
1391 }
dcaf302a 1392 }
1393 else {
1394 $src_text .= qq|use base '$result_base_class';\n\n|;
1395 }
7cab3ab7 1396 $self->_write_classfile($src_class, $src_text);
02356864 1397 }
996be9ee 1398
a4b94090 1399 # remove Result dir if downgrading from use_namespaces, and there are no
1400 # files left.
b5f1b43c 1401 if (my $result_ns = $self->_downgrading_to_load_classes
1402 || $self->_rewriting_result_namespace) {
540a8149 1403 my $result_namespace = $self->_result_namespace(
1404 $schema_class,
1405 $result_ns,
1406 );
a4b94090 1407
540a8149 1408 (my $result_dir = $result_namespace) =~ s{::}{/}g;
a4b94090 1409 $result_dir = $self->dump_directory . '/' . $result_dir;
1410
1411 unless (my @files = glob "$result_dir/*") {
1412 rmdir $result_dir;
1413 }
1414 }
1415
af31090c 1416 warn "Schema dump completed.\n" unless $self->{dynamic} or $self->{quiet};
1417
7cab3ab7 1418}
1419
79193756 1420sub _sig_comment {
1421 my ($self, $version, $ts) = @_;
1422 return qq|\n\n# Created by DBIx::Class::Schema::Loader|
1423 . qq| v| . $version
1424 . q| @ | . $ts
1425 . qq|\n# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:|;
1426}
1427
7cab3ab7 1428sub _write_classfile {
68d49e50 1429 my ($self, $class, $text, $is_schema) = @_;
7cab3ab7 1430
1431 my $filename = $self->_get_dump_filename($class);
1432 $self->_ensure_dump_subdirs($class);
1433
28b4691d 1434 if (-f $filename && $self->really_erase_my_files) {
7cab3ab7 1435 warn "Deleting existing file '$filename' due to "
af31090c 1436 . "'really_erase_my_files' setting\n" unless $self->{quiet};
7cab3ab7 1437 unlink($filename);
8de81918 1438 }
7cab3ab7 1439
8de81918 1440 my ($old_gen, $old_md5, $old_ver, $old_ts, $old_custom)
1441 = $self->_parse_generated_file($filename);
17ca645f 1442
8de81918 1443 if (! $old_gen && -f $filename) {
1444 croak "Cannot overwrite '$filename' without 'really_erase_my_files',"
1445 . " it does not appear to have been generated by Loader"
1446 }
c9cf9b4d 1447
8de81918 1448 my $custom_content = $old_custom || '';
c9cf9b4d 1449
8de81918 1450 # prepend extra custom content from a *renamed* class (singularization effect)
1451 if (my $renamed_class = $self->_upgrading_classes->{$class}) {
1452 my $old_filename = $self->_get_dump_filename($renamed_class);
c9cf9b4d 1453
8de81918 1454 if (-f $old_filename) {
1455 my $extra_custom = ($self->_parse_generated_file ($old_filename))[4];
1456
1457 $extra_custom =~ s/\n\n# You can replace.*\n1;\n//;
1458
1459 $custom_content = join ("\n", '', $extra_custom, $custom_content)
1460 if $extra_custom;
1461
1462 unlink $old_filename;
c9cf9b4d 1463 }
1464 }
1465
49643e1d 1466 $custom_content ||= $self->_default_custom_content($is_schema);
f53dcdf0 1467
8de81918 1468 # If upgrading to use_moose=1 replace default custom content with default Moose custom content.
1469 # If there is already custom content, which does not have the Moose content, add it.
1470 if ($self->use_moose) {
ffc705f3 1471
8de81918 1472 my $non_moose_custom_content = do {
1473 local $self->{use_moose} = 0;
1474 $self->_default_custom_content;
1475 };
f53dcdf0 1476
8de81918 1477 if ($custom_content eq $non_moose_custom_content) {
49643e1d 1478 $custom_content = $self->_default_custom_content($is_schema);
8de81918 1479 }
49643e1d 1480 elsif ($custom_content !~ /\Q@{[$self->_default_moose_custom_content($is_schema)]}\E/) {
1481 $custom_content .= $self->_default_custom_content($is_schema);
f53dcdf0 1482 }
1483 }
22edddda 1484 elsif (defined $self->use_moose && $old_gen) {
1485 croak 'It is not possible to "downgrade" a schema that was loaded with use_moose => 1 to use_moose => 0, due to differing custom content'
1486 if $old_gen =~ /use \s+ MooseX?\b/x;
1487 }
f53dcdf0 1488
b24cb177 1489 $custom_content = $self->_rewrite_old_classnames($custom_content);
1490
7cab3ab7 1491 $text .= qq|$_\n|
1492 for @{$self->{_dump_storage}->{$class} || []};
1493
79193756 1494 # Check and see if the dump is infact differnt
1495
1496 my $compare_to;
1497 if ($old_md5) {
1498 $compare_to = $text . $self->_sig_comment($old_ver, $old_ts);
79193756 1499 if (Digest::MD5::md5_base64($compare_to) eq $old_md5) {
68d49e50 1500 return unless $self->_upgrading_from && $is_schema;
79193756 1501 }
1502 }
1503
1504 $text .= $self->_sig_comment(
01012543 1505 $self->version_to_dump,
79193756 1506 POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime)
1507 );
7cab3ab7 1508
1509 open(my $fh, '>', $filename)
1510 or croak "Cannot open '$filename' for writing: $!";
1511
1512 # Write the top half and its MD5 sum
a4476f41 1513 print $fh $text . Digest::MD5::md5_base64($text) . "\n";
7cab3ab7 1514
1515 # Write out anything loaded via external partial class file in @INC
1516 print $fh qq|$_\n|
1517 for @{$self->{_ext_storage}->{$class} || []};
1518
1eea4fb1 1519 # Write out any custom content the user has added
7cab3ab7 1520 print $fh $custom_content;
1521
1522 close($fh)
e9b8719e 1523 or croak "Error closing '$filename': $!";
7cab3ab7 1524}
1525
c9cf9b4d 1526sub _default_moose_custom_content {
49643e1d 1527 my ($self, $is_schema) = @_;
1528
1529 if (not $is_schema) {
1530 return qq|\n__PACKAGE__->meta->make_immutable;|;
1531 }
1532
1533 return qq|\n__PACKAGE__->meta->make_immutable(inline_constructor => 0);|;
c9cf9b4d 1534}
1535
79193756 1536sub _default_custom_content {
49643e1d 1537 my ($self, $is_schema) = @_;
dcaf302a 1538 my $default = qq|\n\n# You can replace this text with custom|
b8e1a9d5 1539 . qq| code or comments, and it will be preserved on regeneration|;
dcaf302a 1540 if ($self->use_moose) {
49643e1d 1541 $default .= $self->_default_moose_custom_content($is_schema);
dcaf302a 1542 }
1543 $default .= qq|\n1;\n|;
1544 return $default;
79193756 1545}
1546
8de81918 1547sub _parse_generated_file {
1548 my ($self, $fn) = @_;
7cab3ab7 1549
8de81918 1550 return unless -f $fn;
79193756 1551
8de81918 1552 open(my $fh, '<', $fn)
1553 or croak "Cannot open '$fn' for reading: $!";
7cab3ab7 1554
8de81918 1555 my $mark_re =
419a2eeb 1556 qr{^(# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:)([A-Za-z0-9/+]{22})\n};
7cab3ab7 1557
8de81918 1558 my ($md5, $ts, $ver, $gen);
7cab3ab7 1559 while(<$fh>) {
8de81918 1560 if(/$mark_re/) {
1561 my $pre_md5 = $1;
79193756 1562 $md5 = $2;
79193756 1563
8de81918 1564 # Pull out the version and timestamp from the line above
1565 ($ver, $ts) = $gen =~ m/^# Created by DBIx::Class::Schema::Loader v(.*?) @ (.*?)\Z/m;
79193756 1566
8de81918 1567 $gen .= $pre_md5;
1568 croak "Checksum mismatch in '$fn', the auto-generated part of the file has been modified outside of this loader. Aborting.\nIf you want to overwrite these modifications, set the 'overwrite_modifications' loader option.\n"
1569 if !$self->overwrite_modifications && Digest::MD5::md5_base64($gen) ne $md5;
7cab3ab7 1570
8de81918 1571 last;
7cab3ab7 1572 }
1573 else {
8de81918 1574 $gen .= $_;
7cab3ab7 1575 }
996be9ee 1576 }
1577
8de81918 1578 my $custom = do { local $/; <$fh> }
1579 if $md5;
5ef3c771 1580
8de81918 1581 close ($fh);
5ef3c771 1582
8de81918 1583 return ($gen, $md5, $ver, $ts, $custom);
996be9ee 1584}
1585
1586sub _use {
1587 my $self = shift;
1588 my $target = shift;
1589
1590 foreach (@_) {
cb54990b 1591 warn "$target: use $_;" if $self->debug;
996be9ee 1592 $self->_raw_stmt($target, "use $_;");
996be9ee 1593 }
1594}
1595
1596sub _inject {
1597 my $self = shift;
1598 my $target = shift;
996be9ee 1599
af31090c 1600 my $blist = join(q{ }, @_);
6c2b21a5 1601
1602 return unless $blist;
1603
1604 warn "$target: use base qw/$blist/;" if $self->debug;
1605 $self->_raw_stmt($target, "use base qw/$blist/;");
996be9ee 1606}
1607
d36c8734 1608sub _with {
1609 my $self = shift;
1610 my $target = shift;
1611
1612 my $rlist = join(q{, }, map { qq{'$_'} } @_);
1613
1614 return unless $rlist;
1615
1616 warn "$target: with $rlist;" if $self->debug;
1617 $self->_raw_stmt($target, "\nwith $rlist;");
1618}
1619
540a8149 1620sub _result_namespace {
1621 my ($self, $schema_class, $ns) = @_;
1622 my @result_namespace;
1623
1624 if ($ns =~ /^\+(.*)/) {
1625 # Fully qualified namespace
1626 @result_namespace = ($1)
1627 }
1628 else {
1629 # Relative namespace
1630 @result_namespace = ($schema_class, $ns);
1631 }
1632
1633 return wantarray ? @result_namespace : join '::', @result_namespace;
1634}
1635
f96ef30f 1636# Create class with applicable bases, setup monikers, etc
1637sub _make_src_class {
1638 my ($self, $table) = @_;
996be9ee 1639
a13b2803 1640 my $schema = $self->schema;
1641 my $schema_class = $self->schema_class;
996be9ee 1642
f96ef30f 1643 my $table_moniker = $self->_table2moniker($table);
f44ecc2f 1644 my @result_namespace = ($schema_class);
1645 if ($self->use_namespaces) {
1646 my $result_namespace = $self->result_namespace || 'Result';
540a8149 1647 @result_namespace = $self->_result_namespace(
1648 $schema_class,
1649 $result_namespace,
1650 );
f44ecc2f 1651 }
1652 my $table_class = join(q{::}, @result_namespace, $table_moniker);
996be9ee 1653
805dbe0a 1654 if ((my $upgrading_v = $self->_upgrading_from)
a4b94090 1655 || $self->_rewriting) {
805dbe0a 1656 local $self->naming->{monikers} = $upgrading_v
1657 if $upgrading_v;
1658
1659 my @result_namespace = @result_namespace;
a4b94090 1660 if ($self->_upgrading_from_load_classes) {
1661 @result_namespace = ($schema_class);
1662 }
1663 elsif (my $ns = $self->_downgrading_to_load_classes) {
540a8149 1664 @result_namespace = $self->_result_namespace(
1665 $schema_class,
1666 $ns,
1667 );
1668 }
1669 elsif ($ns = $self->_rewriting_result_namespace) {
1670 @result_namespace = $self->_result_namespace(
1671 $schema_class,
1672 $ns,
1673 );
a4b94090 1674 }
f53dcdf0 1675
1676 my $old_class = join(q{::}, @result_namespace,
1677 $self->_table2moniker($table));
1678
68d49e50 1679 $self->_upgrading_classes->{$table_class} = $old_class
1680 unless $table_class eq $old_class;
f53dcdf0 1681 }
1682
d36c8734 1683 $self->classes->{$table} = $table_class;
f96ef30f 1684 $self->monikers->{$table} = $table_moniker;
996be9ee 1685
f96ef30f 1686 $self->_use ($table_class, @{$self->additional_classes});
af31090c 1687 $self->_inject($table_class, @{$self->left_base_classes});
996be9ee 1688
8d65c820 1689 my @components = @{ $self->components || [] };
5ad21d3c 1690
d36c8734 1691 push @components, @{ $self->result_components_map->{$table_moniker} }
1692 if exists $self->result_components_map->{$table_moniker};
5ad21d3c 1693
8d65c820 1694 $self->_dbic_stmt($table_class, 'load_components', @components) if @components;
996be9ee 1695
af31090c 1696 $self->_inject($table_class, @{$self->additional_base_classes});
d36c8734 1697
1698 my @roles = @{ $self->result_roles || [] };
1699 push @roles, @{ $self->result_roles_map->{$table_moniker} }
1700 if exists $self->result_roles_map->{$table_moniker};
1701
1702 $self->_with($table_class, @roles) if @roles;
f96ef30f 1703}
996be9ee 1704
26c54680 1705sub _is_result_class_method {
8d65c820 1706 my ($self, $name, $table_name) = @_;
1707
1708 my $table_moniker = $table_name ? $self->_table2moniker($table_name) : '';
9fdf3d5b 1709
d36c8734 1710 $self->_result_class_methods({})
1711 if not defined $self->_result_class_methods;
1712
1713 if (not exists $self->_result_class_methods->{$table_moniker}) {
26c54680 1714 my (@methods, %methods);
1715 my $base = $self->result_base_class || 'DBIx::Class::Core';
5ad21d3c 1716
1717 my @components = @{ $self->components || [] };
1718
d36c8734 1719 push @components, @{ $self->result_components_map->{$table_moniker} }
1720 if exists $self->result_components_map->{$table_moniker};
5ad21d3c 1721
1722 for my $c (@components) {
1723 $c = $c =~ /^\+/ ? substr($c,1) : "DBIx::Class::$c";
8d65c820 1724 }
9fdf3d5b 1725
d36c8734 1726 my @roles = @{ $self->result_roles || [] };
1727
1728 push @roles, @{ $self->result_roles_map->{$table_moniker} }
1729 if exists $self->result_roles_map->{$table_moniker};
1730
1731 for my $class ($base, @components,
1732 ($self->use_moose ? 'Moose::Object' : ()), @roles) {
7eff9ea3 1733 $self->ensure_class_loaded($class);
15c4393b 1734
26c54680 1735 push @methods, @{ Class::Inspector->methods($class) || [] };
1736 }
9fdf3d5b 1737
26c54680 1738 push @methods, @{ Class::Inspector->methods('UNIVERSAL') };
9fdf3d5b 1739
26c54680 1740 @methods{@methods} = ();
9fdf3d5b 1741
d36c8734 1742 $self->_result_class_methods->{$table_moniker} = \%methods;
a7116285 1743 }
d36c8734 1744 my $result_methods = $self->_result_class_methods->{$table_moniker};
26c54680 1745
1746 return exists $result_methods->{$name};
a7116285 1747}
1748
1749sub _resolve_col_accessor_collisions {
1750 my ($self, $table, $col_info) = @_;
1751
1752 my $table_name = ref $table ? $$table : $table;
6c2b21a5 1753
9fdf3d5b 1754 while (my ($col, $info) = each %$col_info) {
1755 my $accessor = $info->{accessor} || $col;
1756
c9486c78 1757 next if $accessor eq 'id'; # special case (very common column)
9fdf3d5b 1758
8d65c820 1759 if ($self->_is_result_class_method($accessor, $table_name)) {
15c4393b 1760 my $mapped = 0;
1761
1762 if (my $map = $self->col_collision_map) {
1763 for my $re (keys %$map) {
1764 if (my @matches = $col =~ /$re/) {
1765 $info->{accessor} = sprintf $map->{$re}, @matches;
1766 $mapped = 1;
1767 }
1768 }
1769 }
1770
1771 if (not $mapped) {
1772 warn <<"EOF";
a7116285 1773Column '$col' in table '$table_name' collides with an inherited method.
15c4393b 1774See "COLUMN ACCESSOR COLLISIONS" in perldoc DBIx::Class::Schema::Loader::Base .
1775EOF
1776 $info->{accessor} = undef;
1777 }
9fdf3d5b 1778 }
1779 }
1780}
1781
3fea497f 1782# use the same logic to run moniker_map, col_accessor_map, and
cfc5dce3 1783# relationship_name_map
1784sub _run_user_map {
1785 my ( $self, $map, $default_code, $ident, @extra ) = @_;
1786
1787 my $default_ident = $default_code->( $ident, @extra );
1788 my $new_ident;
1789 if( $map && ref $map eq 'HASH' ) {
1790 $new_ident = $map->{ $ident };
1791 }
1792 elsif( $map && ref $map eq 'CODE' ) {
1793 $new_ident = $map->( $ident, $default_ident, @extra );
1794 }
1795
1796 $new_ident ||= $default_ident;
1797
1798 return $new_ident;
1799}
1800
1801sub _default_column_accessor_name {
1802 my ( $self, $column_name ) = @_;
1803
1804 my $accessor_name = $column_name;
1805 $accessor_name =~ s/\W+/_/g;
1806
61d1cca1 1807 if ((($self->naming->{column_accessors}||'') =~ /(\d+)/ && $1 < 7) || (not $self->preserve_case)) {
cfc5dce3 1808 # older naming just lc'd the col accessor and that's all.
1809 return lc $accessor_name;
1810 }
f3a657ef 1811
cc4f11a2 1812 return join '_', map lc, split_name $column_name;
cfc5dce3 1813
1814}
61d1cca1 1815
cfc5dce3 1816sub _make_column_accessor_name {
1817 my ($self, $column_name, $column_context_info ) = @_;
1818
1819 my $accessor = $self->_run_user_map(
3fea497f 1820 $self->col_accessor_map,
cfc5dce3 1821 sub { $self->_default_column_accessor_name( shift ) },
1822 $column_name,
1823 $column_context_info,
1824 );
1825
1826 return $accessor;
f3a657ef 1827}
1828
af31090c 1829# Set up metadata (cols, pks, etc)
f96ef30f 1830sub _setup_src_meta {
1831 my ($self, $table) = @_;
996be9ee 1832
f96ef30f 1833 my $schema = $self->schema;
1834 my $schema_class = $self->schema_class;
a13b2803 1835
f96ef30f 1836 my $table_class = $self->classes->{$table};
1837 my $table_moniker = $self->monikers->{$table};
996be9ee 1838
ff30991a 1839 my $table_name = $table;
1840 my $name_sep = $self->schema->storage->sql_maker->name_sep;
1841
c177d483 1842 if ($name_sep && $table_name =~ /\Q$name_sep\E/) {
ff30991a 1843 $table_name = \ $self->_quote_table_name($table_name);
1844 }
1845
b1d11550 1846 my $full_table_name = ($self->qualify_objects ? ($self->db_schema . '.') : '') . (ref $table_name ? $$table_name : $table_name);
1847
1848 # be careful to not create refs Data::Dump can "optimize"
1849 $full_table_name = \do {"".$full_table_name} if ref $table_name;
1850
1851 $self->_dbic_stmt($table_class, 'table', $full_table_name);
996be9ee 1852
cfc5dce3 1853 my $cols = $self->_table_columns($table);
45be2ce7 1854 my $col_info = $self->__columns_info_for($table);
df55c5fa 1855
cfc5dce3 1856 ### generate all the column accessor names
df55c5fa 1857 while (my ($col, $info) = each %$col_info) {
cfc5dce3 1858 # hashref of other info that could be used by
1859 # user-defined accessor map functions
1860 my $context = {
1861 table_class => $table_class,
1862 table_moniker => $table_moniker,
1863 table_name => $table_name,
1864 full_table_name => $full_table_name,
1865 schema_class => $schema_class,
1866 column_info => $info,
1867 };
df55c5fa 1868
cfc5dce3 1869 $info->{accessor} = $self->_make_column_accessor_name( $col, $context );
45be2ce7 1870 }
c9373b79 1871
15c4393b 1872 $self->_resolve_col_accessor_collisions($full_table_name, $col_info);
9fdf3d5b 1873
cfc5dce3 1874 # prune any redundant accessor names
1875 while (my ($col, $info) = each %$col_info) {
1876 no warnings 'uninitialized';
1877 delete $info->{accessor} if $info->{accessor} eq $col;
1878 }
1879
45be2ce7 1880 my $fks = $self->_table_fk_info($table);
565335e6 1881
10c0c4f3 1882 foreach my $fkdef (@$fks) {
45be2ce7 1883 for my $col (@{ $fkdef->{local_columns} }) {
1884 $col_info->{$col}{is_foreign_key} = 1;
e7213f4f 1885 }
996be9ee 1886 }
10c0c4f3 1887
1888 my $pks = $self->_table_pk_info($table) || [];
1889
1890 foreach my $pkcol (@$pks) {
1891 $col_info->{$pkcol}{is_nullable} = 0;
1892 }
1893
45be2ce7 1894 $self->_dbic_stmt(
1895 $table_class,
1896 'add_columns',
1897 map { $_, ($col_info->{$_}||{}) } @$cols
1898 );
996be9ee 1899
d70c335f 1900 my %uniq_tag; # used to eliminate duplicate uniqs
1901
f96ef30f 1902 @$pks ? $self->_dbic_stmt($table_class,'set_primary_key',@$pks)
1903 : carp("$table has no primary key");
d70c335f 1904 $uniq_tag{ join("\0", @$pks) }++ if @$pks; # pk is a uniq
996be9ee 1905
f96ef30f 1906 my $uniqs = $self->_table_uniq_info($table) || [];
d70c335f 1907 for (@$uniqs) {
1908 my ($name, $cols) = @$_;
1909 next if $uniq_tag{ join("\0", @$cols) }++; # skip duplicates
1910 $self->_dbic_stmt($table_class,'add_unique_constraint', $name, $cols);
1911 }
1912
996be9ee 1913}
1914
d67d058e 1915sub __columns_info_for {
1916 my ($self, $table) = @_;
1917
1918 my $result = $self->_columns_info_for($table);
1919
1920 while (my ($col, $info) = each %$result) {
1921 $info = { %$info, %{ $self->_custom_column_info ($table, $col, $info) } };
1922 $info = { %$info, %{ $self->_datetime_column_info($table, $col, $info) } };
1923
1924 $result->{$col} = $info;
1925 }
1926
1927 return $result;
1928}
1929
996be9ee 1930=head2 tables
1931
1932Returns a sorted list of loaded tables, using the original database table
1933names.
1934
1935=cut
1936
1937sub tables {
1938 my $self = shift;
1939
b97c2c1e 1940 return keys %{$self->_tables};
996be9ee 1941}
1942
1943# Make a moniker from a table
c39e403e 1944sub _default_table2moniker {
66afce69 1945 no warnings 'uninitialized';
c39e403e 1946 my ($self, $table) = @_;
1947
a8d229ff 1948 if ($self->naming->{monikers} eq 'v4') {
1949 return join '', map ucfirst, split /[\W_]+/, lc $table;
1950 }
ecf930e6 1951 elsif ($self->naming->{monikers} eq 'v5') {
1952 return join '', map ucfirst, split /[\W_]+/,
1953 Lingua::EN::Inflect::Number::to_S(lc $table);
1954 }
9990e58f 1955 elsif ($self->naming->{monikers} eq 'v6') {
1956 (my $as_phrase = lc $table) =~ s/_+/ /g;
1957 my $inflected = Lingua::EN::Inflect::Phrase::to_S($as_phrase);
1958
1959 return join '', map ucfirst, split /\W+/, $inflected;
1960 }
1961
cc4f11a2 1962 my @words = map lc, split_name $table;
9990e58f 1963 my $as_phrase = join ' ', @words;
ecf930e6 1964
ecf930e6 1965 my $inflected = Lingua::EN::Inflect::Phrase::to_S($as_phrase);
a8d229ff 1966
ecf930e6 1967 return join '', map ucfirst, split /\W+/, $inflected;
c39e403e 1968}
1969
996be9ee 1970sub _table2moniker {
1971 my ( $self, $table ) = @_;
1972
cfc5dce3 1973 $self->_run_user_map(
1974 $self->moniker_map,
1975 sub { $self->_default_table2moniker( shift ) },
1976 $table
1977 );
996be9ee 1978}
1979
1980sub _load_relationships {
e8ad6491 1981 my ($self, $table) = @_;
996be9ee 1982
e8ad6491 1983 my $tbl_fk_info = $self->_table_fk_info($table);
1984 foreach my $fkdef (@$tbl_fk_info) {
1985 $fkdef->{remote_source} =
1986 $self->monikers->{delete $fkdef->{remote_table}};
996be9ee 1987 }
26f1c8c9 1988 my $tbl_uniq_info = $self->_table_uniq_info($table);
996be9ee 1989
e8ad6491 1990 my $local_moniker = $self->monikers->{$table};
7824616e 1991 my $rel_stmts = $self->_relbuilder->generate_code($local_moniker, $tbl_fk_info, $tbl_uniq_info);
996be9ee 1992
996be9ee 1993 foreach my $src_class (sort keys %$rel_stmts) {
1994 my $src_stmts = $rel_stmts->{$src_class};
1995 foreach my $stmt (@$src_stmts) {
1996 $self->_dbic_stmt($src_class,$stmt->{method},@{$stmt->{args}});
1997 }
1998 }
1999}
2000
2001# Overload these in driver class:
2002
2003# Returns an arrayref of column names
2004sub _table_columns { croak "ABSTRACT METHOD" }
2005
2006# Returns arrayref of pk col names
2007sub _table_pk_info { croak "ABSTRACT METHOD" }
2008
2009# Returns an arrayref of uniqs [ [ foo => [ col1, col2 ] ], [ bar => [ ... ] ] ]
2010sub _table_uniq_info { croak "ABSTRACT METHOD" }
2011
2012# Returns an arrayref of foreign key constraints, each
2013# being a hashref with 3 keys:
2014# local_columns (arrayref), remote_columns (arrayref), remote_table
2015sub _table_fk_info { croak "ABSTRACT METHOD" }
2016
2017# Returns an array of lower case table names
2018sub _tables_list { croak "ABSTRACT METHOD" }
2019
2020# Execute a constructive DBIC class method, with debug/dump_to_dir hooks.
2021sub _dbic_stmt {
bf654ab9 2022 my $self = shift;
2023 my $class = shift;
996be9ee 2024 my $method = shift;
bf654ab9 2025
2026 # generate the pod for this statement, storing it with $self->_pod
43b982ea 2027 $self->_make_pod( $class, $method, @_ ) if $self->generate_pod;
bf654ab9 2028
2029 my $args = dump(@_);
2030 $args = '(' . $args . ')' if @_ < 2;
2031 my $stmt = $method . $args . q{;};
2032
2033 warn qq|$class\->$stmt\n| if $self->debug;
2034 $self->_raw_stmt($class, '__PACKAGE__->' . $stmt);
2035 return;
2036}
2037
2038# generates the accompanying pod for a DBIC class method statement,
2039# storing it with $self->_pod
2040sub _make_pod {
2041 my $self = shift;
2042 my $class = shift;
2043 my $method = shift;
2044
fbcfebdd 2045 if ( $method eq 'table' ) {
2046 my ($table) = @_;
43b982ea 2047 my $pcm = $self->pod_comment_mode;
2048 my ($comment, $comment_overflows, $comment_in_name, $comment_in_desc);
fd97abca 2049 $comment = $self->__table_comment($table);
2050 $comment_overflows = ($comment and length $comment > $self->pod_comment_spillover_length);
2051 $comment_in_name = ($pcm eq 'name' or ($pcm eq 'auto' and !$comment_overflows));
2052 $comment_in_desc = ($pcm eq 'description' or ($pcm eq 'auto' and $comment_overflows));
43b982ea 2053 $self->_pod( $class, "=head1 NAME" );
2054 my $table_descr = $class;
2055 $table_descr .= " - " . $comment if $comment and $comment_in_name;
fbcfebdd 2056 $self->{_class2table}{ $class } = $table;
2057 $self->_pod( $class, $table_descr );
43b982ea 2058 if ($comment and $comment_in_desc) {
2059 $self->_pod( $class, "=head1 DESCRIPTION" );
2060 $self->_pod( $class, $comment );
2061 }
fbcfebdd 2062 $self->_pod_cut( $class );
2063 } elsif ( $method eq 'add_columns' ) {
2064 $self->_pod( $class, "=head1 ACCESSORS" );
79a00530 2065 my $col_counter = 0;
ceb009d3 2066 my @cols = @_;
79a00530 2067 while( my ($name,$attrs) = splice @cols,0,2 ) {
ceb009d3 2068 $col_counter++;
79a00530 2069 $self->_pod( $class, '=head2 ' . $name );
ceb009d3 2070 $self->_pod( $class,
2071 join "\n", map {
2072 my $s = $attrs->{$_};
2073 $s = !defined $s ? 'undef' :
2074 length($s) == 0 ? '(empty string)' :
2075 ref($s) eq 'SCALAR' ? $$s :
2076 ref($s) ? dumper_squashed $s :
2077 looks_like_number($s) ? $s : qq{'$s'};
2078
2079 " $_: $s"
2080 } sort keys %$attrs,
2081 );
4cd5155b 2082 if (my $comment = $self->__column_comment($self->{_class2table}{$class}, $col_counter, $name)) {
ceb009d3 2083 $self->_pod( $class, $comment );
2084 }
fbcfebdd 2085 }
2086 $self->_pod_cut( $class );
2087 } elsif ( $method =~ /^(belongs_to|has_many|might_have)$/ ) {
2088 $self->_pod( $class, "=head1 RELATIONS" ) unless $self->{_relations_started} { $class } ;
2089 my ( $accessor, $rel_class ) = @_;
2090 $self->_pod( $class, "=head2 $accessor" );
2091 $self->_pod( $class, 'Type: ' . $method );
2092 $self->_pod( $class, "Related object: L<$rel_class>" );
2093 $self->_pod_cut( $class );
2094 $self->{_relations_started} { $class } = 1;
2095 }
996be9ee 2096}
2097
fd97abca 2098sub _filter_comment {
2099 my ($self, $txt) = @_;
2100
2101 $txt = '' if not defined $txt;
2102
2103 $txt =~ s/(?:\015?\012|\015\012?)/\n/g;
2104
2105 return $txt;
2106}
2107
2108sub __table_comment {
2109 my $self = shift;
2110
2111 if (my $code = $self->can('_table_comment')) {
2112 return $self->_filter_comment($self->$code(@_));
2113 }
2114
2115 return '';
2116}
2117
2118sub __column_comment {
2119 my $self = shift;
2120
2121 if (my $code = $self->can('_column_comment')) {
2122 return $self->_filter_comment($self->$code(@_));
2123 }
2124
2125 return '';
2126}
2127
fbcfebdd 2128# Stores a POD documentation
2129sub _pod {
2130 my ($self, $class, $stmt) = @_;
2131 $self->_raw_stmt( $class, "\n" . $stmt );
2132}
2133
2134sub _pod_cut {
2135 my ($self, $class ) = @_;
2136 $self->_raw_stmt( $class, "\n=cut\n" );
2137}
2138
996be9ee 2139# Store a raw source line for a class (for dumping purposes)
2140sub _raw_stmt {
2141 my ($self, $class, $stmt) = @_;
af31090c 2142 push(@{$self->{_dump_storage}->{$class}}, $stmt);
996be9ee 2143}
2144
7cab3ab7 2145# Like above, but separately for the externally loaded stuff
2146sub _ext_stmt {
2147 my ($self, $class, $stmt) = @_;
af31090c 2148 push(@{$self->{_ext_storage}->{$class}}, $stmt);
7cab3ab7 2149}
2150
565335e6 2151sub _quote_table_name {
2152 my ($self, $table) = @_;
2153
2154 my $qt = $self->schema->storage->sql_maker->quote_char;
2155
c177d483 2156 return $table unless $qt;
2157
565335e6 2158 if (ref $qt) {
2159 return $qt->[0] . $table . $qt->[1];
2160 }
2161
2162 return $qt . $table . $qt;
2163}
2164
b639d969 2165sub _custom_column_info {
23d1f36b 2166 my ( $self, $table_name, $column_name, $column_info ) = @_;
b639d969 2167
d67d058e 2168 if (my $code = $self->custom_column_info) {
2169 return $code->($table_name, $column_name, $column_info) || {};
b639d969 2170 }
3a368709 2171 return {};
b639d969 2172}
2173
42e785fa 2174sub _datetime_column_info {
23d1f36b 2175 my ( $self, $table_name, $column_name, $column_info ) = @_;
d67d058e 2176 my $result = {};
2177 my $type = $column_info->{data_type} || '';
2178 if ((grep $_, @{ $column_info }{map "inflate_$_", qw/date datetime timestamp/})
2179 or ($type =~ /date|timestamp/i)) {
2180 $result->{timezone} = $self->datetime_timezone if $self->datetime_timezone;
2181 $result->{locale} = $self->datetime_locale if $self->datetime_locale;
42e785fa 2182 }
d67d058e 2183 return $result;
42e785fa 2184}
2185
bc1cb85e 2186sub _lc {
2187 my ($self, $name) = @_;
2188
2189 return $self->preserve_case ? $name : lc($name);
2190}
2191
2192sub _uc {
2193 my ($self, $name) = @_;
2194
2195 return $self->preserve_case ? $name : uc($name);
2196}
2197
0c1d5b47 2198sub _unregister_source_for_table {
2199 my ($self, $table) = @_;
2200
1ad8e8c3 2201 try {
0c1d5b47 2202 local $@;
2203 my $schema = $self->schema;
2204 # in older DBIC it's a private method
2205 my $unregister = $schema->can('unregister_source') || $schema->can('_unregister_source');
2206 $schema->$unregister($self->_table2moniker($table));
2207 delete $self->monikers->{$table};
2208 delete $self->classes->{$table};
2209 delete $self->_upgrading_classes->{$table};
2210 delete $self->{_tables}{$table};
2211 };
2212}
2213
ffc705f3 2214# remove the dump dir from @INC on destruction
2215sub DESTROY {
2216 my $self = shift;
2217
2218 @INC = grep $_ ne $self->dump_directory, @INC;
2219}
2220
996be9ee 2221=head2 monikers
2222
8f9d7ce5 2223Returns a hashref of loaded table to moniker mappings. There will
996be9ee 2224be two entries for each table, the original name and the "normalized"
2225name, in the case that the two are different (such as databases
2226that like uppercase table names, or preserve your original mixed-case
2227definitions, or what-have-you).
2228
2229=head2 classes
2230
8f9d7ce5 2231Returns a hashref of table to class mappings. In some cases it will
996be9ee 2232contain multiple entries per table for the original and normalized table
2233names, as above in L</monikers>.
2234
15c4393b 2235=head1 COLUMN ACCESSOR COLLISIONS
2236
2237Occasionally you may have a column name that collides with a perl method, such
2238as C<can>. In such cases, the default action is to set the C<accessor> of the
2239column spec to C<undef>.
2240
2241You can then name the accessor yourself by placing code such as the following
2242below the md5:
2243
2244 __PACKAGE__->add_column('+can' => { accessor => 'my_can' });
2245
2246Another option is to use the L</col_collision_map> option.
2247
a7116285 2248=head1 RELATIONSHIP NAME COLLISIONS
2249
2250In very rare cases, you may get a collision between a generated relationship
2251name and a method in your Result class, for example if you have a foreign key
2252called C<belongs_to>.
2253
2254This is a problem because relationship names are also relationship accessor
2255methods in L<DBIx::Class>.
2256
2257The default behavior is to append C<_rel> to the relationship name and print
2258out a warning that refers to this text.
2259
2260You can also control the renaming with the L</rel_collision_map> option.
2261
996be9ee 2262=head1 SEE ALSO
2263
2264L<DBIx::Class::Schema::Loader>
2265
be80bba7 2266=head1 AUTHOR
2267
9cc8e7e1 2268See L<DBIx::Class::Schema::Loader/AUTHOR> and L<DBIx::Class::Schema::Loader/CONTRIBUTORS>.
be80bba7 2269
2270=head1 LICENSE
2271
2272This library is free software; you can redistribute it and/or modify it under
2273the same terms as Perl itself.
2274
996be9ee 2275=cut
2276
22771;
bfb43060 2278# vim:et sts=4 sw=4 tw=0: