fix issue w/ M::B and Class::Accessor
[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;
5use base qw/Class::Accessor::Fast/;
6use Class::C3;
fa994d3c 7use Carp::Clan qw/^DBIx::Class/;
996be9ee 8use UNIVERSAL::require;
9use DBIx::Class::Schema::Loader::RelBuilder;
10use Data::Dump qw/ dump /;
11use POSIX qw//;
12require DBIx::Class;
13
32f784fc 14our $VERSION = '0.03999_01';
15
996be9ee 16__PACKAGE__->mk_ro_accessors(qw/
17 schema
18 schema_class
19
20 exclude
21 constraint
22 additional_classes
23 additional_base_classes
24 left_base_classes
25 components
26 resultset_components
27 relationships
28 moniker_map
29 inflect_singular
30 inflect_plural
31 debug
32 dump_directory
d65cda9e 33 dump_overwrite
996be9ee 34
35 legacy_default_inflections
36
37 db_schema
38 _tables
39 classes
40 monikers
41 /);
42
43=head1 NAME
44
45DBIx::Class::Schema::Loader::Base - Base DBIx::Class::Schema::Loader Implementation.
46
47=head1 SYNOPSIS
48
49See L<DBIx::Class::Schema::Loader>
50
51=head1 DESCRIPTION
52
53This is the base class for the storage-specific C<DBIx::Class::Schema::*>
54classes, and implements the common functionality between them.
55
56=head1 CONSTRUCTOR OPTIONS
57
58These constructor options are the base options for
59L<DBIx::Class::Schema::Loader/loader_opts>. Available constructor options are:
60
61=head2 relationships
62
63Try to automatically detect/setup has_a and has_many relationships.
64
65=head2 debug
66
67If set to true, each constructive L<DBIx::Class> statement the loader
68decides to execute will be C<warn>-ed before execution.
69
d65cda9e 70=head2 db_schema
71
72Set the name of the schema to load (schema in the sense that your database
73vendor means it). Does not currently support loading more than one schema
74name.
75
996be9ee 76=head2 constraint
77
78Only load tables matching regex. Best specified as a qr// regex.
79
80=head2 exclude
81
82Exclude tables matching regex. Best specified as a qr// regex.
83
84=head2 moniker_map
85
8f9d7ce5 86Overrides the default table name to moniker translation. Can be either
87a hashref of table keys and moniker values, or a coderef for a translator
996be9ee 88function taking a single scalar table name argument and returning
89a scalar moniker. If the hash entry does not exist, or the function
90returns a false value, the code falls back to default behavior
91for that table name.
92
93The default behavior is: C<join '', map ucfirst, split /[\W_]+/, lc $table>,
94which is to say: lowercase everything, split up the table name into chunks
95anywhere a non-alpha-numeric character occurs, change the case of first letter
96of each chunk to upper case, and put the chunks back together. Examples:
97
98 Table Name | Moniker Name
99 ---------------------------
100 luser | Luser
101 luser_group | LuserGroup
102 luser-opts | LuserOpts
103
104=head2 inflect_plural
105
106Just like L</moniker_map> above (can be hash/code-ref, falls back to default
107if hash key does not exist or coderef returns false), but acts as a map
108for pluralizing relationship names. The default behavior is to utilize
109L<Lingua::EN::Inflect::Number/to_PL>.
110
111=head2 inflect_singular
112
113As L</inflect_plural> above, but for singularizing relationship names.
114Default behavior is to utilize L<Lingua::EN::Inflect::Number/to_S>.
115
116=head2 additional_base_classes
117
118List of additional base classes all of your table classes will use.
119
120=head2 left_base_classes
121
122List of additional base classes all of your table classes will use
123that need to be leftmost.
124
125=head2 additional_classes
126
127List of additional classes which all of your table classes will use.
128
129=head2 components
130
131List of additional components to be loaded into all of your table
132classes. A good example would be C<ResultSetManager>.
133
134=head2 resultset_components
135
8f9d7ce5 136List of additional ResultSet components to be loaded into your table
996be9ee 137classes. A good example would be C<AlwaysRS>. Component
138C<ResultSetManager> will be automatically added to the above
139C<components> list if this option is set.
140
141=head2 legacy_default_inflections
142
143Setting this option changes the default fallback for L</inflect_plural> to
8f9d7ce5 144utilize L<Lingua::EN::Inflect/PL>, and L</inflect_singular> to a no-op.
145Those choices produce substandard results, but might be necessary to support
996be9ee 146your existing code if you started developing on a version prior to 0.03 and
147don't wish to go around updating all your relationship names to the new
148defaults.
149
d65cda9e 150This option will continue to be supported until at least version 0.05xxx,
151but may dissappear sometime thereafter. It is recommended that you update
152your code to use the newer-style inflections when you have the time.
153
996be9ee 154=head2 dump_directory
155
156This option is designed to be a tool to help you transition from this
157loader to a manually-defined schema when you decide it's time to do so.
158
159The value of this option is a perl libdir pathname. Within
160that directory this module will create a baseline manual
161L<DBIx::Class::Schema> module set, based on what it creates at runtime
162in memory.
163
164The created schema class will have the same classname as the one on
165which you are setting this option (and the ResultSource classes will be
166based on this name as well). Therefore it is wise to note that if you
167point the C<dump_directory> option of a schema class at the live libdir
168where that class is currently located, it will overwrite itself with a
169manual version of itself. This might be a really good or bad thing
170depending on your situation and perspective.
171
8f9d7ce5 172Normally you wouldn't hard-code this setting in your schema class, as it
996be9ee 173is meant for one-time manual usage.
174
175See L<DBIx::Class::Schema::Loader/dump_to_dir> for examples of the
176recommended way to access this functionality.
177
d65cda9e 178=head2 dump_overwrite
179
180If set to a true value, the dumping code will overwrite existing files.
02356864 181The default is false, which means the dumping code will skip the already
182existing files.
d65cda9e 183
996be9ee 184=head1 DEPRECATED CONSTRUCTOR OPTIONS
185
d65cda9e 186B<These will be removed in version 0.04000 !!!>
187
996be9ee 188=head2 inflect_map
189
190Equivalent to L</inflect_plural>.
191
192=head2 inflect
193
194Equivalent to L</inflect_plural>.
195
196=head2 connect_info, dsn, user, password, options
197
198You connect these schemas the same way you would any L<DBIx::Class::Schema>,
199which is by calling either C<connect> or C<connection> on a schema class
200or object. These options are only supported via the deprecated
d65cda9e 201C<load_from_connection> interface, which is also being removed in 0.04000.
996be9ee 202
203=head1 METHODS
204
205None of these methods are intended for direct invocation by regular
206users of L<DBIx::Class::Schema::Loader>. Anything you can find here
207can also be found via standard L<DBIx::Class::Schema> methods somehow.
208
209=cut
210
211# ensure that a peice of object data is a valid arrayref, creating
212# an empty one or encapsulating whatever's there.
213sub _ensure_arrayref {
214 my $self = shift;
215
216 foreach (@_) {
217 $self->{$_} ||= [];
218 $self->{$_} = [ $self->{$_} ]
219 unless ref $self->{$_} eq 'ARRAY';
220 }
221}
222
223=head2 new
224
225Constructor for L<DBIx::Class::Schema::Loader::Base>, used internally
226by L<DBIx::Class::Schema::Loader>.
227
228=cut
229
230sub new {
231 my ( $class, %args ) = @_;
232
233 my $self = { %args };
234
235 bless $self => $class;
236
237 $self->{db_schema} ||= '';
238 $self->_ensure_arrayref(qw/additional_classes
239 additional_base_classes
240 left_base_classes
241 components
242 resultset_components
243 /);
244
245 push(@{$self->{components}}, 'ResultSetManager')
246 if @{$self->{resultset_components}};
247
248 $self->{monikers} = {};
249 $self->{classes} = {};
250
251 # Support deprecated arguments
252 for(qw/inflect_map inflect/) {
253 warn "Argument $_ is deprecated in favor of 'inflect_plural'"
d65cda9e 254 . ", and will be removed in 0.04000"
255 if $self->{$_};
996be9ee 256 }
257 $self->{inflect_plural} ||= $self->{inflect_map} || $self->{inflect};
258
259 $self->{schema_class} ||= ( ref $self->{schema} || $self->{schema} );
260 $self->{schema} ||= $self->{schema_class};
261
262 $self;
263}
264
265sub _load_external {
266 my $self = shift;
267
268 foreach my $table_class (values %{$self->classes}) {
269 $table_class->require;
270 if($@ && $@ !~ /^Can't locate /) {
271 croak "Failed to load external class definition"
272 . " for '$table_class': $@";
273 }
274 next if $@; # "Can't locate" error
275
276 # If we make it to here, we loaded an external definition
277 warn qq/# Loaded external class definition for '$table_class'\n/
278 if $self->debug;
279
280 if($self->dump_directory) {
281 my $class_path = $table_class;
282 $class_path =~ s{::}{/}g;
e50425a9 283 $class_path .= '.pm';
996be9ee 284 my $filename = $INC{$class_path};
285 croak 'Failed to locate actual external module file for '
286 . "'$table_class'"
287 if !$filename;
288 open(my $fh, '<', $filename)
289 or croak "Failed to open $filename for reading: $!";
290 $self->_raw_stmt($table_class,
291 q|# These lines loaded from user-supplied external file: |
292 );
293 while(<$fh>) {
294 chomp;
295 $self->_raw_stmt($table_class, $_);
296 }
297 $self->_raw_stmt($table_class,
298 q|# End of lines loaded from user-supplied external file |
299 );
300 close($fh)
301 or croak "Failed to close $filename: $!";
302 }
303 }
304}
305
306=head2 load
307
308Does the actual schema-construction work.
309
310=cut
311
312sub load {
313 my $self = shift;
314
315 $self->_load_classes;
316 $self->_load_relationships if $self->relationships;
317 $self->_load_external;
318 $self->_dump_to_dir if $self->dump_directory;
319
5223f24a 320 # Drop temporary cache
321 delete $self->{_cache};
322
996be9ee 323 1;
324}
325
326sub _get_dump_filename {
327 my ($self, $class) = (@_);
328
329 $class =~ s{::}{/}g;
330 return $self->dump_directory . q{/} . $class . q{.pm};
331}
332
333sub _ensure_dump_subdirs {
334 my ($self, $class) = (@_);
335
336 my @name_parts = split(/::/, $class);
337 pop @name_parts;
338 my $dir = $self->dump_directory;
339 foreach (@name_parts) {
340 $dir .= q{/} . $_;
341 if(! -d $dir) {
25328cc4 342 mkdir($dir) or croak "mkdir('$dir') failed: $!";
996be9ee 343 }
344 }
345}
346
347sub _dump_to_dir {
348 my ($self) = @_;
349
350 my $target_dir = $self->dump_directory;
d65cda9e 351
fc2b71fd 352 my $schema_class = $self->schema_class;
996be9ee 353
25328cc4 354 croak "Must specify target directory for dumping!" if ! $target_dir;
996be9ee 355
fc2b71fd 356 warn "Dumping manual schema for $schema_class to directory $target_dir ...\n";
996be9ee 357
358 if(! -d $target_dir) {
25328cc4 359 mkdir($target_dir) or croak "mkdir('$target_dir') failed: $!";
996be9ee 360 }
361
362 my $verstr = $DBIx::Class::Schema::Loader::VERSION;
363 my $datestr = POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime);
364 my $tagline = qq|# Created by DBIx::Class::Schema::Loader v$verstr @ $datestr|;
365
996be9ee 366 $self->_ensure_dump_subdirs($schema_class);
367
368 my $schema_fn = $self->_get_dump_filename($schema_class);
02356864 369 if (-f $schema_fn && !$self->dump_overwrite) {
370 warn "$schema_fn exists, will not overwrite\n";
371 }
372 else {
373 open(my $schema_fh, '>', $schema_fn)
374 or croak "Cannot open $schema_fn for writing: $!";
375 print $schema_fh qq|package $schema_class;\n\n$tagline\n\n|;
376 print $schema_fh qq|use strict;\nuse warnings;\n\n|;
377 print $schema_fh qq|use base 'DBIx::Class::Schema';\n\n|;
378 print $schema_fh qq|__PACKAGE__->load_classes;\n|;
379 print $schema_fh qq|\n1;\n\n|;
380 close($schema_fh)
381 or croak "Cannot close $schema_fn: $!";
382 }
996be9ee 383
384 foreach my $src_class (sort keys %{$self->{_dump_storage}}) {
385 $self->_ensure_dump_subdirs($src_class);
386 my $src_fn = $self->_get_dump_filename($src_class);
02356864 387 if (-f $src_fn && !$self->dump_overwrite) {
388 warn "$src_fn exists, will not overwrite\n";
389 next;
390 }
996be9ee 391 open(my $src_fh, '>', $src_fn)
25328cc4 392 or croak "Cannot open $src_fn for writing: $!";
996be9ee 393 print $src_fh qq|package $src_class;\n\n$tagline\n\n|;
394 print $src_fh qq|use strict;\nuse warnings;\n\n|;
395 print $src_fh qq|use base 'DBIx::Class';\n\n|;
396 print $src_fh qq|$_\n|
397 for @{$self->{_dump_storage}->{$src_class}};
398 print $src_fh qq|\n1;\n\n|;
399 close($src_fh)
25328cc4 400 or croak "Cannot close $src_fn: $!";
996be9ee 401 }
402
403 warn "Schema dump completed.\n";
404}
405
406sub _use {
407 my $self = shift;
408 my $target = shift;
cb54990b 409 my $evalstr;
996be9ee 410
411 foreach (@_) {
cb54990b 412 warn "$target: use $_;" if $self->debug;
996be9ee 413 $self->_raw_stmt($target, "use $_;");
cb54990b 414 $_->require or croak ($_ . "->require: $@");
415 $evalstr .= "package $target; use $_;";
996be9ee 416 }
cb54990b 417 eval $evalstr if $evalstr;
418 croak $@ if $@;
996be9ee 419}
420
421sub _inject {
422 my $self = shift;
423 my $target = shift;
424 my $schema_class = $self->schema_class;
425
426 my $blist = join(q{ }, @_);
cb54990b 427 warn "$target: use base qw/ $blist /;" if $self->debug && @_;
996be9ee 428 $self->_raw_stmt($target, "use base qw/ $blist /;") if @_;
996be9ee 429 foreach (@_) {
430 $_->require or croak ($_ . "->require: $@");
431 $schema_class->inject_base($target, $_);
432 }
433}
434
435# Load and setup classes
436sub _load_classes {
437 my $self = shift;
438
a13b2803 439 my $schema = $self->schema;
440 my $schema_class = $self->schema_class;
441 my $constraint = $self->constraint;
442 my $exclude = $self->exclude;
443 my @tables = sort $self->_tables_list;
996be9ee 444
445 warn "No tables found in database, nothing to load" if !@tables;
446
447 if(@tables) {
448 @tables = grep { /$constraint/ } @tables if $constraint;
449 @tables = grep { ! /$exclude/ } @tables if $exclude;
450
451 warn "All tables excluded by constraint/exclude, nothing to load"
452 if !@tables;
453 }
454
455 $self->{_tables} = \@tables;
456
457 foreach my $table (@tables) {
458 my $table_moniker = $self->_table2moniker($table);
459 my $table_class = $schema_class . q{::} . $table_moniker;
460
461 my $table_normalized = lc $table;
462 $self->classes->{$table} = $table_class;
463 $self->classes->{$table_normalized} = $table_class;
464 $self->monikers->{$table} = $table_moniker;
465 $self->monikers->{$table_normalized} = $table_moniker;
466
467 no warnings 'redefine';
468 local *Class::C3::reinitialize = sub { };
469 use warnings;
470
a13b2803 471 { no strict 'refs'; @{"${table_class}::ISA"} = qw/DBIx::Class/ }
472
996be9ee 473 $self->_use ($table_class, @{$self->additional_classes});
474 $self->_inject($table_class, @{$self->additional_base_classes});
475
476 $self->_dbic_stmt($table_class, 'load_components', @{$self->components}, qw/PK::Auto Core/);
477
478 $self->_dbic_stmt($table_class, 'load_resultset_components', @{$self->resultset_components})
479 if @{$self->resultset_components};
480 $self->_inject($table_class, @{$self->left_base_classes});
481 }
482
483 Class::C3::reinitialize;
484
485 foreach my $table (@tables) {
486 my $table_class = $self->classes->{$table};
487 my $table_moniker = $self->monikers->{$table};
488
489 $self->_dbic_stmt($table_class,'table',$table);
490
491 my $cols = $self->_table_columns($table);
a13b2803 492 my $col_info;
493 eval { $col_info = $schema->storage->columns_info_for($table) };
494 if($@) {
495 $self->_dbic_stmt($table_class,'add_columns',@$cols);
496 }
497 else {
520107ef 498 my %col_info_lc = map { lc($_), $col_info->{$_} } keys %$col_info;
8ac8926d 499 $self->_dbic_stmt(
500 $table_class,
501 'add_columns',
520107ef 502 map { $_, ($col_info_lc{$_}||{}) } @$cols
8ac8926d 503 );
a13b2803 504 }
996be9ee 505
506 my $pks = $self->_table_pk_info($table) || [];
507 @$pks ? $self->_dbic_stmt($table_class,'set_primary_key',@$pks)
508 : carp("$table has no primary key");
509
510 my $uniqs = $self->_table_uniq_info($table) || [];
511 $self->_dbic_stmt($table_class,'add_unique_constraint',@$_) for (@$uniqs);
512
513 $schema_class->register_class($table_moniker, $table_class);
514 $schema->register_class($table_moniker, $table_class) if $schema ne $schema_class;
515 }
516}
517
518=head2 tables
519
520Returns a sorted list of loaded tables, using the original database table
521names.
522
523=cut
524
525sub tables {
526 my $self = shift;
527
528 return @{$self->_tables};
529}
530
531# Make a moniker from a table
532sub _table2moniker {
533 my ( $self, $table ) = @_;
534
535 my $moniker;
536
537 if( ref $self->moniker_map eq 'HASH' ) {
538 $moniker = $self->moniker_map->{$table};
539 }
540 elsif( ref $self->moniker_map eq 'CODE' ) {
541 $moniker = $self->moniker_map->($table);
542 }
543
544 $moniker ||= join '', map ucfirst, split /[\W_]+/, lc $table;
545
546 return $moniker;
547}
548
549sub _load_relationships {
550 my $self = shift;
551
552 # Construct the fk_info RelBuilder wants to see, by
553 # translating table names to monikers in the _fk_info output
554 my %fk_info;
555 foreach my $table ($self->tables) {
556 my $tbl_fk_info = $self->_table_fk_info($table);
557 foreach my $fkdef (@$tbl_fk_info) {
558 $fkdef->{remote_source} =
559 $self->monikers->{delete $fkdef->{remote_table}};
560 }
561 my $moniker = $self->monikers->{$table};
562 $fk_info{$moniker} = $tbl_fk_info;
563 }
564
565 my $relbuilder = DBIx::Class::Schema::Loader::RelBuilder->new(
566 $self->schema_class, \%fk_info, $self->inflect_plural,
567 $self->inflect_singular
568 );
569
570 my $rel_stmts = $relbuilder->generate_code;
571 foreach my $src_class (sort keys %$rel_stmts) {
572 my $src_stmts = $rel_stmts->{$src_class};
573 foreach my $stmt (@$src_stmts) {
574 $self->_dbic_stmt($src_class,$stmt->{method},@{$stmt->{args}});
575 }
576 }
577}
578
579# Overload these in driver class:
580
581# Returns an arrayref of column names
582sub _table_columns { croak "ABSTRACT METHOD" }
583
584# Returns arrayref of pk col names
585sub _table_pk_info { croak "ABSTRACT METHOD" }
586
587# Returns an arrayref of uniqs [ [ foo => [ col1, col2 ] ], [ bar => [ ... ] ] ]
588sub _table_uniq_info { croak "ABSTRACT METHOD" }
589
590# Returns an arrayref of foreign key constraints, each
591# being a hashref with 3 keys:
592# local_columns (arrayref), remote_columns (arrayref), remote_table
593sub _table_fk_info { croak "ABSTRACT METHOD" }
594
595# Returns an array of lower case table names
596sub _tables_list { croak "ABSTRACT METHOD" }
597
598# Execute a constructive DBIC class method, with debug/dump_to_dir hooks.
599sub _dbic_stmt {
600 my $self = shift;
601 my $class = shift;
602 my $method = shift;
603
604 if(!$self->debug && !$self->dump_directory) {
605 $class->$method(@_);
606 return;
607 }
608
609 my $args = dump(@_);
610 $args = '(' . $args . ')' if @_ < 2;
611 my $stmt = $method . $args . q{;};
612
613 warn qq|$class\->$stmt\n| if $self->debug;
614 $class->$method(@_);
615 $self->_raw_stmt($class, '__PACKAGE__->' . $stmt);
616}
617
618# Store a raw source line for a class (for dumping purposes)
619sub _raw_stmt {
620 my ($self, $class, $stmt) = @_;
621 push(@{$self->{_dump_storage}->{$class}}, $stmt) if $self->dump_directory;
622}
623
624=head2 monikers
625
8f9d7ce5 626Returns a hashref of loaded table to moniker mappings. There will
996be9ee 627be two entries for each table, the original name and the "normalized"
628name, in the case that the two are different (such as databases
629that like uppercase table names, or preserve your original mixed-case
630definitions, or what-have-you).
631
632=head2 classes
633
8f9d7ce5 634Returns a hashref of table to class mappings. In some cases it will
996be9ee 635contain multiple entries per table for the original and normalized table
636names, as above in L</monikers>.
637
638=head1 SEE ALSO
639
640L<DBIx::Class::Schema::Loader>
641
642=cut
643
6441;