1 package DBIx::Class::Schema::Loader::Generic;
7 use Lingua::EN::Inflect;
8 use base qw/Class::Accessor::Fast/;
10 require DBIx::Class::Core;
12 # The first group are all arguments which are may be defaulted within,
13 # The last two (classes, monikers) are generated locally:
15 __PACKAGE__->mk_ro_accessors(qw/
24 additional_base_classes
38 DBIx::Class::Schema::Loader::Generic - Generic DBIx::Class::Schema::Loader Implementation.
42 See L<DBIx::Class::Schema::Loader>
48 Available constructor options are:
50 =head3 additional_base_classes
52 List of additional base classes your table classes will use.
54 =head3 left_base_classes
56 List of additional base classes, that need to be leftmost.
58 =head3 additional_classes
60 List of additional classes which your table classes will use.
64 Only load tables matching regex.
68 Exclude tables matching regex.
72 Enable debug messages.
84 Try to automatically detect/setup has_a and has_many relationships.
88 An hashref, which contains exceptions to Lingua::EN::Inflect::PL().
89 Useful for foreign language column names.
101 Constructor for L<DBIx::Class::Schema::Loader::Generic>, used internally
102 by L<DBIx::Class::Schema::Loader>.
106 # ensure that a peice of object data is a valid arrayref, creating
107 # an empty one or encapsulating whatever's there.
108 sub _ensure_arrayref {
113 $self->{$_} = [ $self->{$_} ]
114 unless ref $self->{$_} eq 'ARRAY';
119 my ( $class, %args ) = @_;
121 my $self = { %args };
123 bless $self => $class;
125 $self->{db_schema} ||= '';
126 $self->{constraint} ||= '.*';
127 $self->{inflect} ||= {};
128 $self->_ensure_arrayref(qw/additional_classes
129 additional_base_classes
132 $self->{monikers} = {};
133 $self->{classes} = {};
135 $self->schema->connection($self->dsn, $self->user,
136 $self->password, $self->options);
138 warn qq/\### START DBIx::Class::Schema::Loader dump ###\n/
141 $self->_load_classes;
142 $self->_load_relationships if $self->relationships;
144 warn qq/\### END DBIx::Class::Schema::Loader dump ###\n/
146 $self->schema->storage->disconnect;
151 # Overload in your driver class
152 sub _db_classes { croak "ABSTRACT METHOD" }
154 # Inflect a relationship name
155 # XXX (should pluralize, but currently also tends to de-pluralize plurals)
156 sub _inflect_relname {
157 my ($self, $relname) = @_;
159 return $self->inflect->{$relname} if exists $self->inflect->{$relname};
160 return Lingua::EN::Inflect::PL($relname);
163 # Set up a simple relation with just a local col and foreign table
164 sub _make_simple_rel {
165 my ($self, $table, $other, $col) = @_;
167 my $table_class = $self->classes->{$table};
168 my $other_class = $self->classes->{$other};
169 my $table_relname = $self->_inflect_relname(lc $table);
171 warn qq/\# Belongs_to relationship\n/ if $self->debug;
172 warn qq/$table_class->belongs_to( '$col' => '$other_class' );\n\n/
174 $table_class->belongs_to( $col => $other_class );
176 warn qq/\# Has_many relationship\n/ if $self->debug;
177 warn qq/$other_class->has_many( '$table_relname' => '$table_class',/
181 $other_class->has_many( $table_relname => $table_class, $col);
184 # not a class method, just a helper for cond_rel XXX
185 sub _stringify_hash {
189 join(q{, }, map("$_ => $href->{$_}", keys %$href))
193 # Set up a complex relation based on a hashref condition
195 my ( $self, $table, $other, $cond ) = @_;
197 my $table_class = $self->classes->{$table};
198 my $other_class = $self->classes->{$other};
199 my $table_relname = $self->_inflect_relname(lc $table);
200 my $other_relname = lc $other;
202 # for single-column case, set the relname to the column name,
203 # to make filter accessors work
204 if(scalar keys %$cond == 1) {
205 my ($col) = keys %$cond;
206 $other_relname = $cond->{$col};
209 my $rev_cond = { reverse %$cond };
211 my $cond_printable = _stringify_hash($cond)
213 my $rev_cond_printable = _stringify_hash($rev_cond)
216 warn qq/\# Belongs_to relationship\n/ if $self->debug;
218 warn qq/$table_class->belongs_to( '$other_relname' => '$other_class',/
219 . qq/$cond_printable);\n\n/
222 $table_class->belongs_to( $other_relname => $other_class, $cond);
224 warn qq/\# Has_many relationship\n/ if $self->debug;
226 warn qq/$other_class->has_many( '$table_relname' => '$table_class',/
227 . qq/$rev_cond_printable);\n\n/
231 $other_class->has_many( $table_relname => $table_class, $rev_cond);
239 $_->require or croak ($_ . "->require: $@");
240 eval "package $target; use $_;";
241 croak "use $_: $@" if $@;
248 my $schema = $self->schema;
251 $_->require or croak ($_ . "->require: $@");
252 $schema->inject_base($target, $_);
256 # Load and setup classes
260 my @tables = $self->_tables();
261 my @db_classes = $self->_db_classes();
262 my $schema = $self->schema;
264 foreach my $table (@tables) {
265 my $constraint = $self->constraint;
266 my $exclude = $self->exclude;
268 next unless $table =~ /$constraint/;
269 next if defined $exclude && $table =~ /$exclude/;
271 my ($db_schema, $tbl) = split /\./, $table;
272 my $tablename = lc $table;
274 $tablename = $self->drop_db_schema ? $tbl : lc $table;
276 my $lc_tblname = lc $tablename;
278 my $table_moniker = $self->_table2moniker($db_schema, $tbl);
279 my $table_class = $schema . q{::} . $table_moniker;
281 $self->_inject($table_class, 'DBIx::Class::Core');
282 $self->_inject($table_class, @db_classes);
283 $self->_inject($table_class, @{$self->additional_base_classes});
284 $self->_use ($table_class, @{$self->additional_classes});
285 $self->_inject($table_class, @{$self->left_base_classes});
287 warn qq/\# Initializing table "$tablename" as "$table_class"\n/
289 $table_class->table($lc_tblname);
291 my ( $cols, $pks ) = $self->_table_info($table);
292 carp("$table has no primary key") unless @$pks;
293 $table_class->add_columns(@$cols);
294 $table_class->set_primary_key(@$pks) if @$pks;
296 warn qq/$table_class->table('$tablename');\n/ if $self->debug;
297 my $columns = join "', '", @$cols;
298 warn qq/$table_class->add_columns('$columns')\n/ if $self->debug;
299 my $primaries = join "', '", @$pks;
300 warn qq/$table_class->set_primary_key('$primaries')\n/
301 if $self->debug && @$pks;
303 $schema->register_class($table_moniker, $table_class);
304 $self->classes->{$lc_tblname} = $table_class;
305 $self->monikers->{$lc_tblname} = $table_moniker;
311 Returns a sorted list of loaded tables, using the original database table
312 names. Actually generated from the keys of the C<monikers> hash below.
314 my @tables = $schema->loader->tables;
318 Returns a hashref of loaded table-to-moniker mappings for the original
319 database table names.
321 my $monikers = $schema->loader->monikers;
322 my $foo_tbl_moniker = $monikers->{foo_tbl};
324 my $foo_tbl_moniker = $schema->loader->monikers->{foo_tbl};
325 # $foo_tbl_moniker would look like "FooTbl"
329 Returns a hashref of table-to-classname mappings for the original database
330 table names. You probably shouldn't be using this, as operating on the
331 original class names is usually a bad idea. This hook is here for people
332 who want to do strange and/or possibly broken things. The usual way to
333 get at things is C<$schema->resultset('FooTbl')>, where C<FooTbl> is a
334 moniker as returned by C<monikers> above.
336 my $classes = $schema->loader->classes;
337 my $foo_tbl_class = $classes->{foo_tbl};
339 my $foo_tbl_class = $schema->loader->classes->{foo_tbl};
340 # $foo_tbl_class would look like "My::Schema::FooTbl",
341 # assuming the schema class is "My::Schema"
348 return sort keys %{ $self->monikers };
351 # Find and setup relationships
352 sub _load_relationships {
355 my $dbh = $self->schema->storage->dbh;
356 my $quoter = $dbh->get_info(29) || q{"};
357 foreach my $table ( $self->tables ) {
359 my $sth = $dbh->foreign_key_info( '',
360 $self->db_schema, '', '', '', $table );
362 while(my $raw_rel = $sth->fetchrow_hashref) {
363 my $uk_tbl = lc $raw_rel->{UK_TABLE_NAME};
364 my $uk_col = lc $raw_rel->{UK_COLUMN_NAME};
365 my $fk_col = lc $raw_rel->{FK_COLUMN_NAME};
366 my $relid = lc $raw_rel->{UK_NAME};
367 $uk_tbl =~ s/$quoter//g;
368 $uk_col =~ s/$quoter//g;
369 $fk_col =~ s/$quoter//g;
370 $relid =~ s/$quoter//g;
371 $rels->{$relid}->{tbl} = $uk_tbl;
372 $rels->{$relid}->{cols}->{$uk_col} = $fk_col;
375 foreach my $relid (keys %$rels) {
376 my $reltbl = $rels->{$relid}->{tbl};
377 my $cond = $rels->{$relid}->{cols};
378 eval { $self->_make_cond_rel( $table, $reltbl, $cond ) };
379 warn qq/\# belongs_to_many failed "$@"\n\n/
380 if $@ && $self->debug;
385 # Make a moniker from a table
387 my ( $self, $db_schema, $table ) = @_;
392 $db_schema = ucfirst lc $db_schema;
393 $db_schema_ns = $db_schema if(!$self->drop_db_schema);
398 my $moniker = join '', map ucfirst, split /[\W_]+/, lc $table;
399 $moniker = $db_schema_ns ? $db_schema_ns . $moniker : $moniker;
404 # Overload in driver class
405 sub _tables { croak "ABSTRACT METHOD" }
407 sub _table_info { croak "ABSTRACT METHOD" }
411 L<DBIx::Class::Schema::Loader>