reverted back to previous compose_namespace method with minor change
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Schema.pm
index 3ce1c1c..3e9d93e 100644 (file)
@@ -7,6 +7,7 @@ use DBIx::Class::Exception;
 use Carp::Clan qw/^DBIx::Class/;
 use Scalar::Util qw/weaken/;
 use File::Spec;
+use Sub::Name ();
 require Module::Find;
 
 use base qw/DBIx::Class/;
@@ -14,7 +15,6 @@ use base qw/DBIx::Class/;
 __PACKAGE__->mk_classdata('class_mappings' => {});
 __PACKAGE__->mk_classdata('source_registrations' => {});
 __PACKAGE__->mk_classdata('storage_type' => '::DBI');
-__PACKAGE__->mk_classdata('storage_type_args' => {});
 __PACKAGE__->mk_classdata('storage');
 __PACKAGE__->mk_classdata('exception_action');
 __PACKAGE__->mk_classdata('stacktrace' => $ENV{DBIC_TRACE} || 0);
@@ -97,7 +97,32 @@ moniker.
 =cut
 
 sub register_source {
-  my ($self, $moniker, $source) = @_;
+  my $self = shift;
+
+  $self->_register_source(@_);
+}
+
+=head2 register_extra_source
+
+=over 4
+
+=item Arguments: $moniker, $result_source
+
+=back
+
+As L</register_source> but should be used if the result class already 
+has a source and you want to register an extra one.
+
+=cut
+
+sub register_extra_source {
+  my $self = shift;
+
+  $self->_register_source(@_, { extra => 1 });
+}
+
+sub _register_source {
+  my ($self, $moniker, $source, $params) = @_;
 
   %$source = %{ $source->new( { %$source, source_name => $moniker }) };
 
@@ -106,10 +131,14 @@ sub register_source {
   $self->source_registrations(\%reg);
 
   $source->schema($self);
-
   weaken($source->{schema}) if ref($self);
+  return if ($params->{extra});
+
   if ($source->result_class) {
     my %map = %{$self->class_mappings};
+    if (exists $map{$source->result_class}) {
+      warn $source->result_class . ' already has a source, use register_extra_source for additional sources';
+    }
     $map{$source->result_class} = $moniker;
     $self->class_mappings(\%map);
   }
@@ -536,7 +565,8 @@ more information.
     my $schema = $self->compose_namespace($target, $base);
     {
       no strict 'refs';
-      *{"${target}::schema"} = sub { $schema };
+      my $name = join '::', $target, 'schema';
+      *$name = Sub::Name::subname $name, sub { $schema };
     }
   
     $schema->connection(@info);
@@ -585,12 +615,31 @@ will produce the output
 
 =cut
 
+# this might be oversimplified
+# sub compose_namespace {
+#   my ($self, $target, $base) = @_;
+
+#   my $schema = $self->clone;
+#   foreach my $moniker ($schema->sources) {
+#     my $source = $schema->source($moniker);
+#     my $target_class = "${target}::${moniker}";
+#     $self->inject_base(
+#       $target_class => $source->result_class, ($base ? $base : ())
+#     );
+#     $source->result_class($target_class);
+#     $target_class->result_source_instance($source)
+#       if $target_class->can('result_source_instance');
+#     $schema->register_source($moniker, $source);
+#   }
+#   return $schema;
+# }
+
 sub compose_namespace {
   my ($self, $target, $base) = @_;
   my $schema = $self->clone;
   {
     no warnings qw/redefine/;
-    local *Class::C3::reinitialize = sub { };
+#    local *Class::C3::reinitialize = sub { };
     foreach my $moniker ($schema->sources) {
       my $source = $schema->source($moniker);
       my $target_class = "${target}::${moniker}";
@@ -600,9 +649,10 @@ sub compose_namespace {
       $source->result_class($target_class);
       $target_class->result_source_instance($source)
         if $target_class->can('result_source_instance');
+     $schema->register_source($moniker, $source);
     }
   }
-  Class::C3->reinitialize();
+#  Class::C3->reinitialize();
   {
     no strict 'refs';
     no warnings 'redefine';
@@ -614,19 +664,6 @@ sub compose_namespace {
   return $schema;
 }
 
-=head2 setup_connection_class
-
-=over 4
-
-=item Arguments: $target, @info
-
-=back
-
-Sets up a database connection class to inject between the schema and the
-subclasses that the schema creates.
-
-=cut
-
 sub setup_connection_class {
   my ($class, $target, @info) = @_;
   $class->inject_base($target => 'DBIx::Class::DB');
@@ -638,9 +675,9 @@ sub setup_connection_class {
 
 =over 4
 
-=item Arguments: $storage_type
+=item Arguments: $storage_type|{$storage_type, \%args}
 
-=item Return Value: $storage_type
+=item Return Value: $storage_type|{$storage_type, \%args}
 
 =back
 
@@ -654,6 +691,13 @@ in cases where the appropriate subclass is not autodetected, such as when
 dealing with MSSQL via L<DBD::Sybase>, in which case you'd set it to
 C<::DBI::Sybase::MSSQL>.
 
+If your storage type requires instantiation arguments, those are defined as a 
+second argument in the form of a hashref and the entire value needs to be
+wrapped into an arrayref or a hashref.  We support both types of refs here in
+order to play nice with your Config::[class] or your choice.
+
+See L<DBIx::Class::Storage::DBI::Replicated> for an example of this.
+
 =head2 connection
 
 =over 4
@@ -676,19 +720,33 @@ or L<DBIx::Class::Storage> in general.
 sub connection {
   my ($self, @info) = @_;
   return $self if !@info && $self->storage;
-  my $storage_class = $self->storage_type;
+  
+  my ($storage_class, $args) = ref $self->storage_type ? 
+    ($self->_normalize_storage_type($self->storage_type),{}) : ($self->storage_type, {});
+    
   $storage_class = 'DBIx::Class::Storage'.$storage_class
     if $storage_class =~ m/^::/;
   eval "require ${storage_class};";
   $self->throw_exception(
     "No arguments to load_classes and couldn't load ${storage_class} ($@)"
   ) if $@;
-  my $storage = $storage_class->new($self, $self->storage_type_args);
+  my $storage = $storage_class->new($self=>$args);
   $storage->connect_info(\@info);
   $self->storage($storage);
   return $self;
 }
 
+sub _normalize_storage_type {
+  my ($self, $storage_type) = @_;
+  if(ref $storage_type eq 'ARRAY') {
+    return @$storage_type;
+  } elsif(ref $storage_type eq 'HASH') {
+    return %$storage_type;
+  } else {
+    $self->throw_exception('Unsupported REFTYPE given: '. ref $storage_type);
+  }
+}
+
 =head2 connect
 
 =over 4
@@ -735,9 +793,10 @@ sub txn_do {
   $self->storage->txn_do(@_);
 }
 
-=head2 txn_scope_guard
+=head2 txn_scope_guard (EXPERIMENTAL)
 
-Runs C<txn_scope_guard> on the schema's storage.
+Runs C<txn_scope_guard> on the schema's storage. See 
+L<DBIx::Class::Storage/txn_scope_guard>.
 
 =cut
 
@@ -870,10 +929,14 @@ sub clone {
   my $clone = { (ref $self ? %$self : ()) };
   bless $clone, (ref $self || $self);
 
+  $clone->class_mappings({ %{$clone->class_mappings} });
+  $clone->source_registrations({ %{$clone->source_registrations} });
   foreach my $moniker ($self->sources) {
     my $source = $self->source($moniker);
     my $new = $source->new($source);
-    $clone->register_source($moniker => $new);
+    # we use extra here as we want to leave the class_mappings as they are
+    # but overwrite the source_registrations entry with the new source
+    $clone->register_extra_source($moniker => $new);
   }
   $clone->storage->set_schema($clone) if $clone->storage;
   return $clone;
@@ -1029,7 +1092,9 @@ produced include a DROP TABLE statement for each table created.
 
 Additionally, the DBIx::Class parser accepts a C<sources> parameter as a hash 
 ref or an array ref, containing a list of source to deploy. If present, then 
-only the sources listed will get deployed.
+only the sources listed will get deployed. Furthermore, you can use the
+C<add_fk_index> parser parameter to prevent the parser from creating an index for each
+FK.
 
 =cut
 
@@ -1083,6 +1148,8 @@ override this method in your schema if you would like a different file
 name format. For the ALTER file, the same format is used, replacing
 $version in the name with "$preversion-$version".
 
+See L<DBIx::Class::Schema/deploy> for details of $sqlt_args.
+
 If no arguments are passed, then the following default values are used:
 
 =over 4
@@ -1111,15 +1178,15 @@ sub create_ddl_dir {
   $self->storage->create_ddl_dir($self, @_);
 }
 
-=head2 ddl_filename (EXPERIMENTAL)
+=head2 ddl_filename
 
 =over 4
 
-=item Arguments: $directory, $database-type, $version, $preversion
+=item Arguments: $database-type, $version, $directory, $preversion
 
 =back
 
-  my $filename = $table->ddl_filename($type, $dir, $version, $preversion)
+  my $filename = $table->ddl_filename($type, $version, $dir, $preversion)
 
 This method is called by C<create_ddl_dir> to compose a file name out of
 the supplied directory, database type and version number. The default file
@@ -1131,14 +1198,14 @@ format.
 =cut
 
 sub ddl_filename {
-    my ($self, $type, $dir, $version, $pversion) = @_;
-
-    my $filename = ref($self);
-    $filename =~ s/::/-/g;
-    $filename = File::Spec->catfile($dir, "$filename-$version-$type.sql");
-    $filename =~ s/$version/$pversion-$version/ if($pversion);
+  my ($self, $type, $version, $dir, $preversion) = @_;
 
-    return $filename;
+  my $filename = ref($self);
+  $filename =~ s/::/-/g;
+  $filename = File::Spec->catfile($dir, "$filename-$version-$type.sql");
+  $filename =~ s/$version/$preversion-$version/ if($preversion);
+  
+  return $filename;
 }
 
 =head2 sqlt_deploy_hook($sqlt_schema)
@@ -1188,6 +1255,29 @@ sub dclone {
   return Storable::dclone($obj);
 }
 
+=head2 schema_version
+
+Returns the current schema class' $VERSION
+
+=cut
+
+sub schema_version {
+  my ($self) = @_;
+  my $class = ref($self)||$self;
+
+  # does -not- use $schema->VERSION
+  # since that varies in results depending on if version.pm is installed, and if
+  # so the perl or XS versions. If you want this to change, bug the version.pm
+  # author to make vpp and vxs behave the same.
+
+  my $version;
+  {
+    no strict 'refs';
+    $version = ${"${class}::VERSION"};
+  }
+  return $version;
+}
+
 1;
 
 =head1 AUTHORS