generate POD for additional_classes, additional_base_classes, left_base_classes,...
[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
42e785fa 67 datetime_timezone
68 datetime_locale
73099af4 69 config_file
71a6e88a 70 loader_class
69219349 71 qualify_objects
65e705c3 72/);
73
996be9ee 74
3d95f9ff 75__PACKAGE__->mk_group_accessors('simple', qw/
01012543 76 version_to_dump
1c95b304 77 schema_version_to_dump
f53dcdf0 78 _upgrading_from
f22644d7 79 _upgrading_from_load_classes
a4b94090 80 _downgrading_to_load_classes
540a8149 81 _rewriting_result_namespace
f22644d7 82 use_namespaces
540a8149 83 result_namespace
492dce8d 84 generate_pod
43b982ea 85 pod_comment_mode
86 pod_comment_spillover_length
bc1cb85e 87 preserve_case
15c4393b 88 col_collision_map
a7116285 89 rel_collision_map
1ad8e8c3 90 real_dump_directory
d36c8734 91 result_components_map
92 result_roles_map
57a9fc92 93 datetime_undef_if_invalid
26c54680 94 _result_class_methods
7cbfc0c1 95 naming_set
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
42ea7b88 768 if (not $self->naming_set) {
66afce69 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
38fd5f91 784 if ((not defined $self->use_namespaces) && ($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
4f807130 1190 $self->_load_roles($_) for @tables;
1191
f96ef30f 1192 $self->_load_external($_)
75451704 1193 for map { $self->classes->{$_} } @tables;
f96ef30f 1194
106a976a 1195 # Reload without unloading first to preserve any symbols from external
1196 # packages.
1ad8e8c3 1197 $self->_reload_classes(\@tables, { unload => 0 });
996be9ee 1198
5223f24a 1199 # Drop temporary cache
1200 delete $self->{_cache};
1201
c39e3507 1202 return \@tables;
996be9ee 1203}
1204
af31090c 1205sub _reload_classes {
1ad8e8c3 1206 my ($self, $tables, $opts) = @_;
106a976a 1207
1208 my @tables = @$tables;
1ad8e8c3 1209
1210 my $unload = $opts->{unload};
106a976a 1211 $unload = 1 unless defined $unload;
181cc907 1212
4daef04f 1213 # so that we don't repeat custom sections
1214 @INC = grep $_ ne $self->dump_directory, @INC;
1215
181cc907 1216 $self->_dump_to_dir(map { $self->classes->{$_} } @tables);
e9b8719e 1217
1218 unshift @INC, $self->dump_directory;
af31090c 1219
706ef173 1220 my @to_register;
1221 my %have_source = map { $_ => $self->schema->source($_) }
1222 $self->schema->sources;
1223
181cc907 1224 for my $table (@tables) {
1225 my $moniker = $self->monikers->{$table};
1226 my $class = $self->classes->{$table};
0ae6b65d 1227
1228 {
1229 no warnings 'redefine';
942bd5e0 1230 local *Class::C3::reinitialize = sub {}; # to speed things up, reinitialized below
0ae6b65d 1231 use warnings;
1232
01f93238 1233 if (my $mc = $self->_moose_metaclass($class)) {
1234 $mc->make_mutable;
c9cf9b4d 1235 }
106a976a 1236 Class::Unload->unload($class) if $unload;
706ef173 1237 my ($source, $resultset_class);
1238 if (
1239 ($source = $have_source{$moniker})
1240 && ($resultset_class = $source->resultset_class)
1241 && ($resultset_class ne 'DBIx::Class::ResultSet')
1242 ) {
1243 my $has_file = Class::Inspector->loaded_filename($resultset_class);
01f93238 1244 if (my $mc = $self->_moose_metaclass($resultset_class)) {
1245 $mc->make_mutable;
c9cf9b4d 1246 }
106a976a 1247 Class::Unload->unload($resultset_class) if $unload;
1248 $self->_reload_class($resultset_class) if $has_file;
0ae6b65d 1249 }
106a976a 1250 $self->_reload_class($class);
af31090c 1251 }
706ef173 1252 push @to_register, [$moniker, $class];
1253 }
af31090c 1254
706ef173 1255 Class::C3->reinitialize;
1256 for (@to_register) {
1257 $self->schema->register_class(@$_);
af31090c 1258 }
1259}
1260
01f93238 1261sub _moose_metaclass {
1262 return undef unless $INC{'Class/MOP.pm'}; # if CMOP is not loaded the class could not have loaded in the 1st place
1263
0dd4099e 1264 my $class = $_[1];
1265
1266 my $mc = try { Class::MOP::class_of($class) }
01f93238 1267 or return undef;
1268
1269 return $mc->isa('Moose::Meta::Class') ? $mc : undef;
1270}
1271
106a976a 1272# We use this instead of ensure_class_loaded when there are package symbols we
1273# want to preserve.
1274sub _reload_class {
1275 my ($self, $class) = @_;
1276
0f21885a 1277 delete $INC{ +class_path($class) };
f53dcdf0 1278
1ad8e8c3 1279 try {
0f21885a 1280 eval_package_without_redefine_warnings ($class, "require $class");
1ad8e8c3 1281 }
1282 catch {
61d1cca1 1283 my $source = slurp $self->_get_dump_filename($class);
1284 die "Failed to reload class $class: $_.\n\nCLASS SOURCE:\n\n$source";
f53dcdf0 1285 };
106a976a 1286}
1287
996be9ee 1288sub _get_dump_filename {
1289 my ($self, $class) = (@_);
1290
1291 $class =~ s{::}{/}g;
1292 return $self->dump_directory . q{/} . $class . q{.pm};
1293}
1294
1ad8e8c3 1295=head2 get_dump_filename
1296
1297Arguments: class
1298
1299Returns the full path to the file for a class that the class has been or will
1300be dumped to. This is a file in a temp dir for a dynamic schema.
1301
1302=cut
1303
1304sub get_dump_filename {
1305 my ($self, $class) = (@_);
1306
1307 local $self->{dump_directory} = $self->real_dump_directory;
1308
1309 return $self->_get_dump_filename($class);
1310}
1311
996be9ee 1312sub _ensure_dump_subdirs {
1313 my ($self, $class) = (@_);
1314
1315 my @name_parts = split(/::/, $class);
dd03ee1a 1316 pop @name_parts; # we don't care about the very last element,
1317 # which is a filename
1318
996be9ee 1319 my $dir = $self->dump_directory;
7cab3ab7 1320 while (1) {
1321 if(!-d $dir) {
25328cc4 1322 mkdir($dir) or croak "mkdir('$dir') failed: $!";
996be9ee 1323 }
7cab3ab7 1324 last if !@name_parts;
1325 $dir = File::Spec->catdir($dir, shift @name_parts);
996be9ee 1326 }
1327}
1328
1329sub _dump_to_dir {
af31090c 1330 my ($self, @classes) = @_;
996be9ee 1331
fc2b71fd 1332 my $schema_class = $self->schema_class;
9c9c2f2b 1333 my $schema_base_class = $self->schema_base_class || 'DBIx::Class::Schema';
996be9ee 1334
e9b8719e 1335 my $target_dir = $self->dump_directory;
af31090c 1336 warn "Dumping manual schema for $schema_class to directory $target_dir ...\n"
1337 unless $self->{dynamic} or $self->{quiet};
996be9ee 1338
7cab3ab7 1339 my $schema_text =
1340 qq|package $schema_class;\n\n|
b4dcbcc5 1341 . qq|# Created by DBIx::Class::Schema::Loader\n|
1ad8e8c3 1342 . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|;
1343
dcaf302a 1344 if ($self->use_moose) {
49643e1d 1345 $schema_text.= qq|use Moose;\nuse namespace::autoclean;\nextends '$schema_base_class';\n\n|;
dcaf302a 1346 }
1347 else {
1ad8e8c3 1348 $schema_text .= qq|use strict;\nuse warnings;\n\nuse base '$schema_base_class';\n\n|;
dcaf302a 1349 }
f44ecc2f 1350
f44ecc2f 1351 if ($self->use_namespaces) {
1352 $schema_text .= qq|__PACKAGE__->load_namespaces|;
1353 my $namespace_options;
2a8e93e9 1354
1355 my @attr = qw/resultset_namespace default_resultset_class/;
1356
1357 unshift @attr, 'result_namespace' unless (not $self->result_namespace) || $self->result_namespace eq 'Result';
1358
1359 for my $attr (@attr) {
f44ecc2f 1360 if ($self->$attr) {
1361 $namespace_options .= qq| $attr => '| . $self->$attr . qq|',\n|
1362 }
1363 }
1364 $schema_text .= qq|(\n$namespace_options)| if $namespace_options;
1365 $schema_text .= qq|;\n|;
1366 }
1367 else {
1368 $schema_text .= qq|__PACKAGE__->load_classes;\n|;
f44ecc2f 1369 }
996be9ee 1370
1c95b304 1371 {
1372 local $self->{version_to_dump} = $self->schema_version_to_dump;
68d49e50 1373 $self->_write_classfile($schema_class, $schema_text, 1);
1c95b304 1374 }
996be9ee 1375
2229729e 1376 my $result_base_class = $self->result_base_class || 'DBIx::Class::Core';
9c9c2f2b 1377
af31090c 1378 foreach my $src_class (@classes) {
7cab3ab7 1379 my $src_text =
1380 qq|package $src_class;\n\n|
b4dcbcc5 1381 . qq|# Created by DBIx::Class::Schema::Loader\n|
1382 . qq|# DO NOT MODIFY THE FIRST PART OF THIS FILE\n\n|
dcaf302a 1383 . qq|use strict;\nuse warnings;\n\n|;
1384 if ($self->use_moose) {
6c2b21a5 1385 $src_text.= qq|use Moose;\nuse MooseX::NonMoose;\nuse namespace::autoclean;|;
1386
1387 # these options 'use base' which is compile time
2b74a06b 1388 if (@{ $self->left_base_classes } || @{ $self->additional_base_classes }) {
6c2b21a5 1389 $src_text .= qq|\nBEGIN { extends '$result_base_class' }\n\n|;
1390 }
1391 else {
1392 $src_text .= qq|\nextends '$result_base_class';\n\n|;
1393 }
dcaf302a 1394 }
1395 else {
1396 $src_text .= qq|use base '$result_base_class';\n\n|;
1397 }
7cab3ab7 1398 $self->_write_classfile($src_class, $src_text);
02356864 1399 }
996be9ee 1400
a4b94090 1401 # remove Result dir if downgrading from use_namespaces, and there are no
1402 # files left.
b5f1b43c 1403 if (my $result_ns = $self->_downgrading_to_load_classes
1404 || $self->_rewriting_result_namespace) {
540a8149 1405 my $result_namespace = $self->_result_namespace(
1406 $schema_class,
1407 $result_ns,
1408 );
a4b94090 1409
540a8149 1410 (my $result_dir = $result_namespace) =~ s{::}{/}g;
a4b94090 1411 $result_dir = $self->dump_directory . '/' . $result_dir;
1412
1413 unless (my @files = glob "$result_dir/*") {
1414 rmdir $result_dir;
1415 }
1416 }
1417
af31090c 1418 warn "Schema dump completed.\n" unless $self->{dynamic} or $self->{quiet};
1419
7cab3ab7 1420}
1421
79193756 1422sub _sig_comment {
1423 my ($self, $version, $ts) = @_;
1424 return qq|\n\n# Created by DBIx::Class::Schema::Loader|
1425 . qq| v| . $version
1426 . q| @ | . $ts
1427 . qq|\n# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:|;
1428}
1429
7cab3ab7 1430sub _write_classfile {
68d49e50 1431 my ($self, $class, $text, $is_schema) = @_;
7cab3ab7 1432
1433 my $filename = $self->_get_dump_filename($class);
1434 $self->_ensure_dump_subdirs($class);
1435
28b4691d 1436 if (-f $filename && $self->really_erase_my_files) {
7cab3ab7 1437 warn "Deleting existing file '$filename' due to "
af31090c 1438 . "'really_erase_my_files' setting\n" unless $self->{quiet};
7cab3ab7 1439 unlink($filename);
8de81918 1440 }
7cab3ab7 1441
8de81918 1442 my ($old_gen, $old_md5, $old_ver, $old_ts, $old_custom)
1443 = $self->_parse_generated_file($filename);
17ca645f 1444
8de81918 1445 if (! $old_gen && -f $filename) {
1446 croak "Cannot overwrite '$filename' without 'really_erase_my_files',"
1447 . " it does not appear to have been generated by Loader"
1448 }
c9cf9b4d 1449
8de81918 1450 my $custom_content = $old_custom || '';
c9cf9b4d 1451
8de81918 1452 # prepend extra custom content from a *renamed* class (singularization effect)
1453 if (my $renamed_class = $self->_upgrading_classes->{$class}) {
1454 my $old_filename = $self->_get_dump_filename($renamed_class);
c9cf9b4d 1455
8de81918 1456 if (-f $old_filename) {
1457 my $extra_custom = ($self->_parse_generated_file ($old_filename))[4];
1458
1459 $extra_custom =~ s/\n\n# You can replace.*\n1;\n//;
1460
1461 $custom_content = join ("\n", '', $extra_custom, $custom_content)
1462 if $extra_custom;
1463
1464 unlink $old_filename;
c9cf9b4d 1465 }
1466 }
1467
49643e1d 1468 $custom_content ||= $self->_default_custom_content($is_schema);
f53dcdf0 1469
8de81918 1470 # If upgrading to use_moose=1 replace default custom content with default Moose custom content.
1471 # If there is already custom content, which does not have the Moose content, add it.
1472 if ($self->use_moose) {
ffc705f3 1473
8de81918 1474 my $non_moose_custom_content = do {
1475 local $self->{use_moose} = 0;
1476 $self->_default_custom_content;
1477 };
f53dcdf0 1478
8de81918 1479 if ($custom_content eq $non_moose_custom_content) {
49643e1d 1480 $custom_content = $self->_default_custom_content($is_schema);
8de81918 1481 }
49643e1d 1482 elsif ($custom_content !~ /\Q@{[$self->_default_moose_custom_content($is_schema)]}\E/) {
1483 $custom_content .= $self->_default_custom_content($is_schema);
f53dcdf0 1484 }
1485 }
22edddda 1486 elsif (defined $self->use_moose && $old_gen) {
1487 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'
1488 if $old_gen =~ /use \s+ MooseX?\b/x;
1489 }
f53dcdf0 1490
b24cb177 1491 $custom_content = $self->_rewrite_old_classnames($custom_content);
1492
7cab3ab7 1493 $text .= qq|$_\n|
1494 for @{$self->{_dump_storage}->{$class} || []};
1495
79193756 1496 # Check and see if the dump is infact differnt
1497
1498 my $compare_to;
1499 if ($old_md5) {
1500 $compare_to = $text . $self->_sig_comment($old_ver, $old_ts);
79193756 1501 if (Digest::MD5::md5_base64($compare_to) eq $old_md5) {
68d49e50 1502 return unless $self->_upgrading_from && $is_schema;
79193756 1503 }
1504 }
1505
1506 $text .= $self->_sig_comment(
01012543 1507 $self->version_to_dump,
79193756 1508 POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime)
1509 );
7cab3ab7 1510
1511 open(my $fh, '>', $filename)
1512 or croak "Cannot open '$filename' for writing: $!";
1513
1514 # Write the top half and its MD5 sum
a4476f41 1515 print $fh $text . Digest::MD5::md5_base64($text) . "\n";
7cab3ab7 1516
1517 # Write out anything loaded via external partial class file in @INC
1518 print $fh qq|$_\n|
1519 for @{$self->{_ext_storage}->{$class} || []};
1520
1eea4fb1 1521 # Write out any custom content the user has added
7cab3ab7 1522 print $fh $custom_content;
1523
1524 close($fh)
e9b8719e 1525 or croak "Error closing '$filename': $!";
7cab3ab7 1526}
1527
c9cf9b4d 1528sub _default_moose_custom_content {
49643e1d 1529 my ($self, $is_schema) = @_;
1530
1531 if (not $is_schema) {
1532 return qq|\n__PACKAGE__->meta->make_immutable;|;
1533 }
1534
1535 return qq|\n__PACKAGE__->meta->make_immutable(inline_constructor => 0);|;
c9cf9b4d 1536}
1537
79193756 1538sub _default_custom_content {
49643e1d 1539 my ($self, $is_schema) = @_;
dcaf302a 1540 my $default = qq|\n\n# You can replace this text with custom|
b8e1a9d5 1541 . qq| code or comments, and it will be preserved on regeneration|;
dcaf302a 1542 if ($self->use_moose) {
49643e1d 1543 $default .= $self->_default_moose_custom_content($is_schema);
dcaf302a 1544 }
1545 $default .= qq|\n1;\n|;
1546 return $default;
79193756 1547}
1548
8de81918 1549sub _parse_generated_file {
1550 my ($self, $fn) = @_;
7cab3ab7 1551
8de81918 1552 return unless -f $fn;
79193756 1553
8de81918 1554 open(my $fh, '<', $fn)
1555 or croak "Cannot open '$fn' for reading: $!";
7cab3ab7 1556
8de81918 1557 my $mark_re =
419a2eeb 1558 qr{^(# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:)([A-Za-z0-9/+]{22})\n};
7cab3ab7 1559
8de81918 1560 my ($md5, $ts, $ver, $gen);
7cab3ab7 1561 while(<$fh>) {
8de81918 1562 if(/$mark_re/) {
1563 my $pre_md5 = $1;
79193756 1564 $md5 = $2;
79193756 1565
8de81918 1566 # Pull out the version and timestamp from the line above
1567 ($ver, $ts) = $gen =~ m/^# Created by DBIx::Class::Schema::Loader v(.*?) @ (.*?)\Z/m;
79193756 1568
8de81918 1569 $gen .= $pre_md5;
1570 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"
1571 if !$self->overwrite_modifications && Digest::MD5::md5_base64($gen) ne $md5;
7cab3ab7 1572
8de81918 1573 last;
7cab3ab7 1574 }
1575 else {
8de81918 1576 $gen .= $_;
7cab3ab7 1577 }
996be9ee 1578 }
1579
8de81918 1580 my $custom = do { local $/; <$fh> }
1581 if $md5;
5ef3c771 1582
8de81918 1583 close ($fh);
5ef3c771 1584
8de81918 1585 return ($gen, $md5, $ver, $ts, $custom);
996be9ee 1586}
1587
1588sub _use {
1589 my $self = shift;
1590 my $target = shift;
1591
1592 foreach (@_) {
cb54990b 1593 warn "$target: use $_;" if $self->debug;
996be9ee 1594 $self->_raw_stmt($target, "use $_;");
996be9ee 1595 }
1596}
1597
1598sub _inject {
1599 my $self = shift;
1600 my $target = shift;
996be9ee 1601
af31090c 1602 my $blist = join(q{ }, @_);
6c2b21a5 1603
1604 return unless $blist;
1605
1606 warn "$target: use base qw/$blist/;" if $self->debug;
1607 $self->_raw_stmt($target, "use base qw/$blist/;");
996be9ee 1608}
1609
d36c8734 1610sub _with {
1611 my $self = shift;
1612 my $target = shift;
1613
1614 my $rlist = join(q{, }, map { qq{'$_'} } @_);
1615
1616 return unless $rlist;
1617
1618 warn "$target: with $rlist;" if $self->debug;
1619 $self->_raw_stmt($target, "\nwith $rlist;");
1620}
1621
540a8149 1622sub _result_namespace {
1623 my ($self, $schema_class, $ns) = @_;
1624 my @result_namespace;
1625
1626 if ($ns =~ /^\+(.*)/) {
1627 # Fully qualified namespace
1628 @result_namespace = ($1)
1629 }
1630 else {
1631 # Relative namespace
1632 @result_namespace = ($schema_class, $ns);
1633 }
1634
1635 return wantarray ? @result_namespace : join '::', @result_namespace;
1636}
1637
f96ef30f 1638# Create class with applicable bases, setup monikers, etc
1639sub _make_src_class {
1640 my ($self, $table) = @_;
996be9ee 1641
a13b2803 1642 my $schema = $self->schema;
1643 my $schema_class = $self->schema_class;
996be9ee 1644
f96ef30f 1645 my $table_moniker = $self->_table2moniker($table);
f44ecc2f 1646 my @result_namespace = ($schema_class);
1647 if ($self->use_namespaces) {
1648 my $result_namespace = $self->result_namespace || 'Result';
540a8149 1649 @result_namespace = $self->_result_namespace(
1650 $schema_class,
1651 $result_namespace,
1652 );
f44ecc2f 1653 }
1654 my $table_class = join(q{::}, @result_namespace, $table_moniker);
996be9ee 1655
805dbe0a 1656 if ((my $upgrading_v = $self->_upgrading_from)
a4b94090 1657 || $self->_rewriting) {
805dbe0a 1658 local $self->naming->{monikers} = $upgrading_v
1659 if $upgrading_v;
1660
1661 my @result_namespace = @result_namespace;
a4b94090 1662 if ($self->_upgrading_from_load_classes) {
1663 @result_namespace = ($schema_class);
1664 }
1665 elsif (my $ns = $self->_downgrading_to_load_classes) {
540a8149 1666 @result_namespace = $self->_result_namespace(
1667 $schema_class,
1668 $ns,
1669 );
1670 }
1671 elsif ($ns = $self->_rewriting_result_namespace) {
1672 @result_namespace = $self->_result_namespace(
1673 $schema_class,
1674 $ns,
1675 );
a4b94090 1676 }
f53dcdf0 1677
1678 my $old_class = join(q{::}, @result_namespace,
1679 $self->_table2moniker($table));
1680
68d49e50 1681 $self->_upgrading_classes->{$table_class} = $old_class
1682 unless $table_class eq $old_class;
f53dcdf0 1683 }
1684
d36c8734 1685 $self->classes->{$table} = $table_class;
f96ef30f 1686 $self->monikers->{$table} = $table_moniker;
996be9ee 1687
06e06245 1688 $self->_pod_class_list($table_class, 'ADDITIONAL CLASSES USED', @{$self->additional_classes});
1689
f96ef30f 1690 $self->_use ($table_class, @{$self->additional_classes});
06e06245 1691
1692 $self->_pod_class_list($table_class, 'LEFT BASE CLASSES', @{$self->left_base_classes});
1693
af31090c 1694 $self->_inject($table_class, @{$self->left_base_classes});
996be9ee 1695
8d65c820 1696 my @components = @{ $self->components || [] };
5ad21d3c 1697
d36c8734 1698 push @components, @{ $self->result_components_map->{$table_moniker} }
1699 if exists $self->result_components_map->{$table_moniker};
5ad21d3c 1700
06e06245 1701 my @fq_components = @components;
1702 foreach my $component (@fq_components) {
1703 if ($component !~ s/^\+//) {
1704 $component = "DBIx::Class::$component";
1705 }
1706 }
1707
1708 $self->_pod_class_list($table_class, 'COMPONENTS LOADED', @fq_components);
1709
8d65c820 1710 $self->_dbic_stmt($table_class, 'load_components', @components) if @components;
996be9ee 1711
06e06245 1712 $self->_pod_class_list($table_class, 'ADDITIONAL BASE CLASSES', @{$self->additional_base_classes});
1713
af31090c 1714 $self->_inject($table_class, @{$self->additional_base_classes});
f96ef30f 1715}
996be9ee 1716
26c54680 1717sub _is_result_class_method {
8d65c820 1718 my ($self, $name, $table_name) = @_;
1719
1720 my $table_moniker = $table_name ? $self->_table2moniker($table_name) : '';
9fdf3d5b 1721
d36c8734 1722 $self->_result_class_methods({})
1723 if not defined $self->_result_class_methods;
1724
1725 if (not exists $self->_result_class_methods->{$table_moniker}) {
26c54680 1726 my (@methods, %methods);
1727 my $base = $self->result_base_class || 'DBIx::Class::Core';
5ad21d3c 1728
1729 my @components = @{ $self->components || [] };
1730
d36c8734 1731 push @components, @{ $self->result_components_map->{$table_moniker} }
1732 if exists $self->result_components_map->{$table_moniker};
5ad21d3c 1733
1734 for my $c (@components) {
1735 $c = $c =~ /^\+/ ? substr($c,1) : "DBIx::Class::$c";
8d65c820 1736 }
9fdf3d5b 1737
d36c8734 1738 my @roles = @{ $self->result_roles || [] };
1739
1740 push @roles, @{ $self->result_roles_map->{$table_moniker} }
1741 if exists $self->result_roles_map->{$table_moniker};
1742
1743 for my $class ($base, @components,
1744 ($self->use_moose ? 'Moose::Object' : ()), @roles) {
7eff9ea3 1745 $self->ensure_class_loaded($class);
15c4393b 1746
26c54680 1747 push @methods, @{ Class::Inspector->methods($class) || [] };
1748 }
9fdf3d5b 1749
26c54680 1750 push @methods, @{ Class::Inspector->methods('UNIVERSAL') };
9fdf3d5b 1751
26c54680 1752 @methods{@methods} = ();
9fdf3d5b 1753
d36c8734 1754 $self->_result_class_methods->{$table_moniker} = \%methods;
a7116285 1755 }
d36c8734 1756 my $result_methods = $self->_result_class_methods->{$table_moniker};
26c54680 1757
1758 return exists $result_methods->{$name};
a7116285 1759}
1760
1761sub _resolve_col_accessor_collisions {
1762 my ($self, $table, $col_info) = @_;
1763
1764 my $table_name = ref $table ? $$table : $table;
6c2b21a5 1765
9fdf3d5b 1766 while (my ($col, $info) = each %$col_info) {
1767 my $accessor = $info->{accessor} || $col;
1768
c9486c78 1769 next if $accessor eq 'id'; # special case (very common column)
9fdf3d5b 1770
8d65c820 1771 if ($self->_is_result_class_method($accessor, $table_name)) {
15c4393b 1772 my $mapped = 0;
1773
1774 if (my $map = $self->col_collision_map) {
1775 for my $re (keys %$map) {
1776 if (my @matches = $col =~ /$re/) {
1777 $info->{accessor} = sprintf $map->{$re}, @matches;
1778 $mapped = 1;
1779 }
1780 }
1781 }
1782
1783 if (not $mapped) {
1784 warn <<"EOF";
a7116285 1785Column '$col' in table '$table_name' collides with an inherited method.
15c4393b 1786See "COLUMN ACCESSOR COLLISIONS" in perldoc DBIx::Class::Schema::Loader::Base .
1787EOF
1788 $info->{accessor} = undef;
1789 }
9fdf3d5b 1790 }
1791 }
1792}
1793
3fea497f 1794# use the same logic to run moniker_map, col_accessor_map, and
cfc5dce3 1795# relationship_name_map
1796sub _run_user_map {
1797 my ( $self, $map, $default_code, $ident, @extra ) = @_;
1798
1799 my $default_ident = $default_code->( $ident, @extra );
1800 my $new_ident;
1801 if( $map && ref $map eq 'HASH' ) {
1802 $new_ident = $map->{ $ident };
1803 }
1804 elsif( $map && ref $map eq 'CODE' ) {
1805 $new_ident = $map->( $ident, $default_ident, @extra );
1806 }
1807
1808 $new_ident ||= $default_ident;
1809
1810 return $new_ident;
1811}
1812
1813sub _default_column_accessor_name {
1814 my ( $self, $column_name ) = @_;
1815
1816 my $accessor_name = $column_name;
1817 $accessor_name =~ s/\W+/_/g;
1818
61d1cca1 1819 if ((($self->naming->{column_accessors}||'') =~ /(\d+)/ && $1 < 7) || (not $self->preserve_case)) {
cfc5dce3 1820 # older naming just lc'd the col accessor and that's all.
1821 return lc $accessor_name;
1822 }
f3a657ef 1823
cc4f11a2 1824 return join '_', map lc, split_name $column_name;
cfc5dce3 1825
1826}
61d1cca1 1827
cfc5dce3 1828sub _make_column_accessor_name {
1829 my ($self, $column_name, $column_context_info ) = @_;
1830
1831 my $accessor = $self->_run_user_map(
3fea497f 1832 $self->col_accessor_map,
cfc5dce3 1833 sub { $self->_default_column_accessor_name( shift ) },
1834 $column_name,
1835 $column_context_info,
1836 );
1837
1838 return $accessor;
f3a657ef 1839}
1840
af31090c 1841# Set up metadata (cols, pks, etc)
f96ef30f 1842sub _setup_src_meta {
1843 my ($self, $table) = @_;
996be9ee 1844
f96ef30f 1845 my $schema = $self->schema;
1846 my $schema_class = $self->schema_class;
a13b2803 1847
4f807130 1848 my $table_class = $self->classes->{$table};
f96ef30f 1849 my $table_moniker = $self->monikers->{$table};
996be9ee 1850
ff30991a 1851 my $table_name = $table;
1852 my $name_sep = $self->schema->storage->sql_maker->name_sep;
1853
c177d483 1854 if ($name_sep && $table_name =~ /\Q$name_sep\E/) {
ff30991a 1855 $table_name = \ $self->_quote_table_name($table_name);
1856 }
1857
b1d11550 1858 my $full_table_name = ($self->qualify_objects ? ($self->db_schema . '.') : '') . (ref $table_name ? $$table_name : $table_name);
1859
1860 # be careful to not create refs Data::Dump can "optimize"
1861 $full_table_name = \do {"".$full_table_name} if ref $table_name;
1862
1863 $self->_dbic_stmt($table_class, 'table', $full_table_name);
996be9ee 1864
cfc5dce3 1865 my $cols = $self->_table_columns($table);
45be2ce7 1866 my $col_info = $self->__columns_info_for($table);
df55c5fa 1867
cfc5dce3 1868 ### generate all the column accessor names
df55c5fa 1869 while (my ($col, $info) = each %$col_info) {
cfc5dce3 1870 # hashref of other info that could be used by
1871 # user-defined accessor map functions
1872 my $context = {
1873 table_class => $table_class,
1874 table_moniker => $table_moniker,
1875 table_name => $table_name,
1876 full_table_name => $full_table_name,
1877 schema_class => $schema_class,
1878 column_info => $info,
1879 };
df55c5fa 1880
cfc5dce3 1881 $info->{accessor} = $self->_make_column_accessor_name( $col, $context );
45be2ce7 1882 }
c9373b79 1883
15c4393b 1884 $self->_resolve_col_accessor_collisions($full_table_name, $col_info);
9fdf3d5b 1885
cfc5dce3 1886 # prune any redundant accessor names
1887 while (my ($col, $info) = each %$col_info) {
1888 no warnings 'uninitialized';
1889 delete $info->{accessor} if $info->{accessor} eq $col;
1890 }
1891
45be2ce7 1892 my $fks = $self->_table_fk_info($table);
565335e6 1893
10c0c4f3 1894 foreach my $fkdef (@$fks) {
45be2ce7 1895 for my $col (@{ $fkdef->{local_columns} }) {
1896 $col_info->{$col}{is_foreign_key} = 1;
e7213f4f 1897 }
996be9ee 1898 }
10c0c4f3 1899
1900 my $pks = $self->_table_pk_info($table) || [];
1901
1902 foreach my $pkcol (@$pks) {
1903 $col_info->{$pkcol}{is_nullable} = 0;
1904 }
1905
45be2ce7 1906 $self->_dbic_stmt(
1907 $table_class,
1908 'add_columns',
1909 map { $_, ($col_info->{$_}||{}) } @$cols
1910 );
996be9ee 1911
d70c335f 1912 my %uniq_tag; # used to eliminate duplicate uniqs
1913
f96ef30f 1914 @$pks ? $self->_dbic_stmt($table_class,'set_primary_key',@$pks)
1915 : carp("$table has no primary key");
d70c335f 1916 $uniq_tag{ join("\0", @$pks) }++ if @$pks; # pk is a uniq
996be9ee 1917
f96ef30f 1918 my $uniqs = $self->_table_uniq_info($table) || [];
d70c335f 1919 for (@$uniqs) {
1920 my ($name, $cols) = @$_;
1921 next if $uniq_tag{ join("\0", @$cols) }++; # skip duplicates
1922 $self->_dbic_stmt($table_class,'add_unique_constraint', $name, $cols);
1923 }
1924
996be9ee 1925}
1926
d67d058e 1927sub __columns_info_for {
1928 my ($self, $table) = @_;
1929
1930 my $result = $self->_columns_info_for($table);
1931
1932 while (my ($col, $info) = each %$result) {
1933 $info = { %$info, %{ $self->_custom_column_info ($table, $col, $info) } };
1934 $info = { %$info, %{ $self->_datetime_column_info($table, $col, $info) } };
1935
1936 $result->{$col} = $info;
1937 }
1938
1939 return $result;
1940}
1941
996be9ee 1942=head2 tables
1943
1944Returns a sorted list of loaded tables, using the original database table
1945names.
1946
1947=cut
1948
1949sub tables {
1950 my $self = shift;
1951
b97c2c1e 1952 return keys %{$self->_tables};
996be9ee 1953}
1954
1955# Make a moniker from a table
c39e403e 1956sub _default_table2moniker {
66afce69 1957 no warnings 'uninitialized';
c39e403e 1958 my ($self, $table) = @_;
1959
a8d229ff 1960 if ($self->naming->{monikers} eq 'v4') {
1961 return join '', map ucfirst, split /[\W_]+/, lc $table;
1962 }
ecf930e6 1963 elsif ($self->naming->{monikers} eq 'v5') {
1964 return join '', map ucfirst, split /[\W_]+/,
1965 Lingua::EN::Inflect::Number::to_S(lc $table);
1966 }
9990e58f 1967 elsif ($self->naming->{monikers} eq 'v6') {
1968 (my $as_phrase = lc $table) =~ s/_+/ /g;
1969 my $inflected = Lingua::EN::Inflect::Phrase::to_S($as_phrase);
1970
1971 return join '', map ucfirst, split /\W+/, $inflected;
1972 }
1973
cc4f11a2 1974 my @words = map lc, split_name $table;
9990e58f 1975 my $as_phrase = join ' ', @words;
ecf930e6 1976
ecf930e6 1977 my $inflected = Lingua::EN::Inflect::Phrase::to_S($as_phrase);
a8d229ff 1978
ecf930e6 1979 return join '', map ucfirst, split /\W+/, $inflected;
c39e403e 1980}
1981
996be9ee 1982sub _table2moniker {
1983 my ( $self, $table ) = @_;
1984
cfc5dce3 1985 $self->_run_user_map(
1986 $self->moniker_map,
1987 sub { $self->_default_table2moniker( shift ) },
1988 $table
1989 );
996be9ee 1990}
1991
1992sub _load_relationships {
e8ad6491 1993 my ($self, $table) = @_;
996be9ee 1994
e8ad6491 1995 my $tbl_fk_info = $self->_table_fk_info($table);
1996 foreach my $fkdef (@$tbl_fk_info) {
1997 $fkdef->{remote_source} =
1998 $self->monikers->{delete $fkdef->{remote_table}};
996be9ee 1999 }
26f1c8c9 2000 my $tbl_uniq_info = $self->_table_uniq_info($table);
996be9ee 2001
e8ad6491 2002 my $local_moniker = $self->monikers->{$table};
7824616e 2003 my $rel_stmts = $self->_relbuilder->generate_code($local_moniker, $tbl_fk_info, $tbl_uniq_info);
996be9ee 2004
996be9ee 2005 foreach my $src_class (sort keys %$rel_stmts) {
2006 my $src_stmts = $rel_stmts->{$src_class};
2007 foreach my $stmt (@$src_stmts) {
2008 $self->_dbic_stmt($src_class,$stmt->{method},@{$stmt->{args}});
2009 }
2010 }
2011}
2012
4f807130 2013sub _load_roles {
2014 my ($self, $table) = @_;
2015
2016 my $table_moniker = $self->monikers->{$table};
2017 my $table_class = $self->classes->{$table};
2018
2019 my @roles = @{ $self->result_roles || [] };
2020 push @roles, @{ $self->result_roles_map->{$table_moniker} }
2021 if exists $self->result_roles_map->{$table_moniker};
2022
06e06245 2023 if (@roles) {
2024 $self->_pod_class_list($table_class, 'L<Moose> ROLES APPLIED', @roles);
2025
2026 $self->_with($table_class, @roles);
2027 }
4f807130 2028}
2029
996be9ee 2030# Overload these in driver class:
2031
2032# Returns an arrayref of column names
2033sub _table_columns { croak "ABSTRACT METHOD" }
2034
2035# Returns arrayref of pk col names
2036sub _table_pk_info { croak "ABSTRACT METHOD" }
2037
2038# Returns an arrayref of uniqs [ [ foo => [ col1, col2 ] ], [ bar => [ ... ] ] ]
2039sub _table_uniq_info { croak "ABSTRACT METHOD" }
2040
2041# Returns an arrayref of foreign key constraints, each
2042# being a hashref with 3 keys:
2043# local_columns (arrayref), remote_columns (arrayref), remote_table
2044sub _table_fk_info { croak "ABSTRACT METHOD" }
2045
2046# Returns an array of lower case table names
2047sub _tables_list { croak "ABSTRACT METHOD" }
2048
2049# Execute a constructive DBIC class method, with debug/dump_to_dir hooks.
2050sub _dbic_stmt {
bf654ab9 2051 my $self = shift;
2052 my $class = shift;
996be9ee 2053 my $method = shift;
bf654ab9 2054
2055 # generate the pod for this statement, storing it with $self->_pod
43b982ea 2056 $self->_make_pod( $class, $method, @_ ) if $self->generate_pod;
bf654ab9 2057
2058 my $args = dump(@_);
2059 $args = '(' . $args . ')' if @_ < 2;
2060 my $stmt = $method . $args . q{;};
2061
2062 warn qq|$class\->$stmt\n| if $self->debug;
2063 $self->_raw_stmt($class, '__PACKAGE__->' . $stmt);
2064 return;
2065}
2066
2067# generates the accompanying pod for a DBIC class method statement,
2068# storing it with $self->_pod
2069sub _make_pod {
2070 my $self = shift;
2071 my $class = shift;
2072 my $method = shift;
2073
fbcfebdd 2074 if ( $method eq 'table' ) {
2075 my ($table) = @_;
43b982ea 2076 my $pcm = $self->pod_comment_mode;
2077 my ($comment, $comment_overflows, $comment_in_name, $comment_in_desc);
fd97abca 2078 $comment = $self->__table_comment($table);
2079 $comment_overflows = ($comment and length $comment > $self->pod_comment_spillover_length);
2080 $comment_in_name = ($pcm eq 'name' or ($pcm eq 'auto' and !$comment_overflows));
2081 $comment_in_desc = ($pcm eq 'description' or ($pcm eq 'auto' and $comment_overflows));
43b982ea 2082 $self->_pod( $class, "=head1 NAME" );
2083 my $table_descr = $class;
2084 $table_descr .= " - " . $comment if $comment and $comment_in_name;
fbcfebdd 2085 $self->{_class2table}{ $class } = $table;
2086 $self->_pod( $class, $table_descr );
43b982ea 2087 if ($comment and $comment_in_desc) {
2088 $self->_pod( $class, "=head1 DESCRIPTION" );
2089 $self->_pod( $class, $comment );
2090 }
fbcfebdd 2091 $self->_pod_cut( $class );
2092 } elsif ( $method eq 'add_columns' ) {
2093 $self->_pod( $class, "=head1 ACCESSORS" );
79a00530 2094 my $col_counter = 0;
ceb009d3 2095 my @cols = @_;
79a00530 2096 while( my ($name,$attrs) = splice @cols,0,2 ) {
ceb009d3 2097 $col_counter++;
79a00530 2098 $self->_pod( $class, '=head2 ' . $name );
ceb009d3 2099 $self->_pod( $class,
2100 join "\n", map {
2101 my $s = $attrs->{$_};
2102 $s = !defined $s ? 'undef' :
2103 length($s) == 0 ? '(empty string)' :
2104 ref($s) eq 'SCALAR' ? $$s :
2105 ref($s) ? dumper_squashed $s :
2106 looks_like_number($s) ? $s : qq{'$s'};
2107
2108 " $_: $s"
2109 } sort keys %$attrs,
2110 );
4cd5155b 2111 if (my $comment = $self->__column_comment($self->{_class2table}{$class}, $col_counter, $name)) {
ceb009d3 2112 $self->_pod( $class, $comment );
2113 }
fbcfebdd 2114 }
2115 $self->_pod_cut( $class );
2116 } elsif ( $method =~ /^(belongs_to|has_many|might_have)$/ ) {
2117 $self->_pod( $class, "=head1 RELATIONS" ) unless $self->{_relations_started} { $class } ;
2118 my ( $accessor, $rel_class ) = @_;
2119 $self->_pod( $class, "=head2 $accessor" );
2120 $self->_pod( $class, 'Type: ' . $method );
2121 $self->_pod( $class, "Related object: L<$rel_class>" );
2122 $self->_pod_cut( $class );
2123 $self->{_relations_started} { $class } = 1;
2124 }
996be9ee 2125}
2126
06e06245 2127sub _pod_class_list {
2128 my ($self, $class, $title, @classes) = @_;
2129
2130 return unless @classes && $self->generate_pod;
2131
2132 $self->_pod($class, "=head1 $title");
2133 $self->_pod($class, '=over 4');
2134
2135 foreach my $link (@classes) {
2136 $self->_pod($class, "=item L<$link>");
2137 }
2138
2139 $self->_pod($class, '=back');
2140 $self->_pod_cut($class);
2141}
2142
fd97abca 2143sub _filter_comment {
2144 my ($self, $txt) = @_;
2145
2146 $txt = '' if not defined $txt;
2147
2148 $txt =~ s/(?:\015?\012|\015\012?)/\n/g;
2149
2150 return $txt;
2151}
2152
2153sub __table_comment {
2154 my $self = shift;
2155
2156 if (my $code = $self->can('_table_comment')) {
2157 return $self->_filter_comment($self->$code(@_));
2158 }
2159
2160 return '';
2161}
2162
2163sub __column_comment {
2164 my $self = shift;
2165
2166 if (my $code = $self->can('_column_comment')) {
2167 return $self->_filter_comment($self->$code(@_));
2168 }
2169
2170 return '';
2171}
2172
fbcfebdd 2173# Stores a POD documentation
2174sub _pod {
2175 my ($self, $class, $stmt) = @_;
2176 $self->_raw_stmt( $class, "\n" . $stmt );
2177}
2178
2179sub _pod_cut {
2180 my ($self, $class ) = @_;
2181 $self->_raw_stmt( $class, "\n=cut\n" );
2182}
2183
996be9ee 2184# Store a raw source line for a class (for dumping purposes)
2185sub _raw_stmt {
2186 my ($self, $class, $stmt) = @_;
af31090c 2187 push(@{$self->{_dump_storage}->{$class}}, $stmt);
996be9ee 2188}
2189
7cab3ab7 2190# Like above, but separately for the externally loaded stuff
2191sub _ext_stmt {
2192 my ($self, $class, $stmt) = @_;
af31090c 2193 push(@{$self->{_ext_storage}->{$class}}, $stmt);
7cab3ab7 2194}
2195
565335e6 2196sub _quote_table_name {
2197 my ($self, $table) = @_;
2198
2199 my $qt = $self->schema->storage->sql_maker->quote_char;
2200
c177d483 2201 return $table unless $qt;
2202
565335e6 2203 if (ref $qt) {
2204 return $qt->[0] . $table . $qt->[1];
2205 }
2206
2207 return $qt . $table . $qt;
2208}
2209
b639d969 2210sub _custom_column_info {
23d1f36b 2211 my ( $self, $table_name, $column_name, $column_info ) = @_;
b639d969 2212
d67d058e 2213 if (my $code = $self->custom_column_info) {
2214 return $code->($table_name, $column_name, $column_info) || {};
b639d969 2215 }
3a368709 2216 return {};
b639d969 2217}
2218
42e785fa 2219sub _datetime_column_info {
23d1f36b 2220 my ( $self, $table_name, $column_name, $column_info ) = @_;
d67d058e 2221 my $result = {};
2222 my $type = $column_info->{data_type} || '';
2223 if ((grep $_, @{ $column_info }{map "inflate_$_", qw/date datetime timestamp/})
2224 or ($type =~ /date|timestamp/i)) {
2225 $result->{timezone} = $self->datetime_timezone if $self->datetime_timezone;
2226 $result->{locale} = $self->datetime_locale if $self->datetime_locale;
42e785fa 2227 }
d67d058e 2228 return $result;
42e785fa 2229}
2230
bc1cb85e 2231sub _lc {
2232 my ($self, $name) = @_;
2233
2234 return $self->preserve_case ? $name : lc($name);
2235}
2236
2237sub _uc {
2238 my ($self, $name) = @_;
2239
2240 return $self->preserve_case ? $name : uc($name);
2241}
2242
0c1d5b47 2243sub _unregister_source_for_table {
2244 my ($self, $table) = @_;
2245
1ad8e8c3 2246 try {
0c1d5b47 2247 local $@;
2248 my $schema = $self->schema;
2249 # in older DBIC it's a private method
2250 my $unregister = $schema->can('unregister_source') || $schema->can('_unregister_source');
2251 $schema->$unregister($self->_table2moniker($table));
2252 delete $self->monikers->{$table};
2253 delete $self->classes->{$table};
2254 delete $self->_upgrading_classes->{$table};
2255 delete $self->{_tables}{$table};
2256 };
2257}
2258
ffc705f3 2259# remove the dump dir from @INC on destruction
2260sub DESTROY {
2261 my $self = shift;
2262
2263 @INC = grep $_ ne $self->dump_directory, @INC;
2264}
2265
996be9ee 2266=head2 monikers
2267
8f9d7ce5 2268Returns a hashref of loaded table to moniker mappings. There will
996be9ee 2269be two entries for each table, the original name and the "normalized"
2270name, in the case that the two are different (such as databases
2271that like uppercase table names, or preserve your original mixed-case
2272definitions, or what-have-you).
2273
2274=head2 classes
2275
8f9d7ce5 2276Returns a hashref of table to class mappings. In some cases it will
996be9ee 2277contain multiple entries per table for the original and normalized table
2278names, as above in L</monikers>.
2279
15c4393b 2280=head1 COLUMN ACCESSOR COLLISIONS
2281
2282Occasionally you may have a column name that collides with a perl method, such
2283as C<can>. In such cases, the default action is to set the C<accessor> of the
2284column spec to C<undef>.
2285
2286You can then name the accessor yourself by placing code such as the following
2287below the md5:
2288
2289 __PACKAGE__->add_column('+can' => { accessor => 'my_can' });
2290
2291Another option is to use the L</col_collision_map> option.
2292
a7116285 2293=head1 RELATIONSHIP NAME COLLISIONS
2294
2295In very rare cases, you may get a collision between a generated relationship
2296name and a method in your Result class, for example if you have a foreign key
2297called C<belongs_to>.
2298
2299This is a problem because relationship names are also relationship accessor
2300methods in L<DBIx::Class>.
2301
2302The default behavior is to append C<_rel> to the relationship name and print
2303out a warning that refers to this text.
2304
2305You can also control the renaming with the L</rel_collision_map> option.
2306
996be9ee 2307=head1 SEE ALSO
2308
2309L<DBIx::Class::Schema::Loader>
2310
be80bba7 2311=head1 AUTHOR
2312
9cc8e7e1 2313See L<DBIx::Class::Schema::Loader/AUTHOR> and L<DBIx::Class::Schema::Loader/CONTRIBUTORS>.
be80bba7 2314
2315=head1 LICENSE
2316
2317This library is free software; you can redistribute it and/or modify it under
2318the same terms as Perl itself.
2319
996be9ee 2320=cut
2321
23221;
bfb43060 2323# vim:et sts=4 sw=4 tw=0: