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