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