CustomVariable-RDBO-Helfer: Dokumentation aktualisiert
[kivitendo-erp.git] / SL / DB / Helper / CustomVariables.pm
index e8c7d6b..6f47035 100644 (file)
@@ -4,7 +4,6 @@ use strict;
 use Carp;
 use Data::Dumper;
 use List::Util qw(first);
-use SL::DB::CustomVariableConfig;
 
 use constant META_CVARS => 'cvars_config';
 
@@ -18,15 +17,16 @@ sub import {
 
   $params{module}     ||= _calc_modules_from_overloads(%params) if $params{overloads};
   $params{sub_module} ||= '';
-  $params{id}         ||= 'id';
+  $params{id}         ||= _get_primary_key_column($caller_package);
 
   $params{module} || $params{sub_module}  or croak 'need param module or sub_module';
 
-  save_meta_info($caller_package, %params);
+  return unless save_meta_info($caller_package, %params);
   make_cvar_accessor($caller_package, %params);
   make_cvar_alias($caller_package, %params)      if $params{cvars_alias};
   make_cvar_by_configs($caller_package, %params);
   make_cvar_by_name($caller_package, %params);
+  make_cvar_as_hashref($caller_package, %params);
 }
 
 sub save_meta_info {
@@ -36,21 +36,25 @@ sub save_meta_info {
   return 0 if $meta->{META_CVARS()};
 
   $meta->{META_CVARS()} = \%params;
+
+  return 1;
 }
 
 sub make_cvar_accessor {
   my ($caller_package, %params) = @_;
 
-  my @module_filter = $params{module} ?
-    ("config.module" => $params{module}) :
+  my $modules = ('ARRAY' eq ref $params{module}) ?
+      join ',', @{ $params{module} } :
+      $params{module};
+  my @module_filter = $modules ?
+    ("config_id" => [ \"(SELECT custom_variable_configs.id FROM custom_variable_configs WHERE custom_variable_configs.module IN ( '$modules' ))" ]) : # " make emacs happy
     ();
 
   $caller_package->meta->add_relationships(
     custom_variables => {
       type         => 'one to many',
       class        => 'SL::DB::CustomVariable',
-      column_map   => { ($params{id} || 'id') => 'trans_id' },
-      manager_args => { with_objects => 'config' },
+      column_map   => { $params{id} => 'trans_id' },
       query_args   => [ sub_module => $params{sub_module}, @module_filter ],
     }
   );
@@ -65,7 +69,7 @@ sub make_cvar_alias {
 }
 
 # this is used for templates where you need to list every applicable config
-# auto vivifies non existant cvar objects as necessary.
+# auto vivifies non existent cvar objects as necessary.
 sub make_cvar_by_configs {
   my ($caller_package, %params) = @_;
 
@@ -78,7 +82,19 @@ sub make_cvar_by_configs {
     my $cvars       = $self->custom_variables;
     my %cvars_by_config = map { $_->config_id => $_ } @$cvars;
 
-    my @return  = map { $cvars_by_config{$_->id} || _new_cvar($self, %params, config => $_) } @$configs;
+    my @return = map(
+      {
+        if ( $cvars_by_config{$_->id} ) {
+          $cvars_by_config{$_->id};
+        }
+        else {
+          my $cvar = _new_cvar($self, %params, config => $_);
+          $self->add_custom_variables($cvar);
+          $cvar;
+        }
+      }
+      @$configs
+    );
 
     return \@return;
   }
@@ -110,18 +126,38 @@ sub make_cvar_by_name {
   }
 }
 
+sub make_cvar_as_hashref {
+  my ($caller_package, %params) = @_;
+
+  no strict 'refs';
+  *{ $caller_package . '::cvar_as_hashref' } = sub {
+    my ($self) = @_;
+    @_ > 1 and croak "not an accessor";
+
+    my $cvars_by_config = $self->cvars_by_config;
+
+    my %return = map {
+      $_->config->name => { value => $_->value_as_text, is_valid => $_->is_valid }
+    } @$cvars_by_config;
+
+    return \%return;
+  }
+}
+
 sub _all_configs {
   my (%params) = @_;
-  $params{module}
-    ? SL::DB::Manager::CustomVariableConfig->get_all(query => [ module => $params{module} ])
-    : SL::DB::Manager::CustomVariableConfig->get_all;
+
+  require SL::DB::CustomVariableConfig;
+
+  SL::DB::Manager::CustomVariableConfig->get_all_sorted($params{module} ? (query => [ module => $params{module} ]) : ());
 }
 
 sub _overload_by_module {
   my ($module, %params) = @_;
 
-  while (my ($fk, $class) = each %{ $params{overloads} }) {
-    return ($fk, $class) if $class->meta->{META_CVARS()}->{module} eq $module;
+  keys %{ $params{overloads} }; # reset each iterator
+  while (my ($fk, $def) = each %{ $params{overloads} }) {
+    return ($fk, $def->{class}) if $def->{module} eq $module;
   }
 
   croak "unknown overload, cannot resolve module $module";
@@ -153,16 +189,24 @@ sub _calc_modules_from_overloads {
   my (%params) = @_;
   my %modules;
 
-  while (my ($fk, $class) = each %{ $params{overloads} }) {
-    eval "require $class"; # make sure the class is loaded
-    my $module = $class->meta->{META_CVARS()}->{module};
-    next if ref $module;
-    $modules{$module} = 1;
+  for my $def (values %{ $params{overloads} || {} }) {
+    $modules{$def->{module}} = 1;
   }
 
   return [ keys %modules ];
 }
 
+sub _get_primary_key_column {
+  my ($caller_package) = @_;
+  my $meta             = $caller_package->meta;
+
+  my $column_name;
+  $column_name = $meta->{primary_key}->{columns}->[0] if $meta->{primary_key} && (ref($meta->{primary_key}->{columns}) eq 'ARRAY') && (1 == scalar(@{ $meta->{primary_key}->{columns} }));
+
+  croak "Unable to retrieve primary key column name: meta information for package $caller_package not set up correctly" unless $column_name;
+
+  return $column_name;
+}
 
 1;
 
@@ -187,7 +231,10 @@ SL::DB::Helper::CustomVariables - Mixin to provide custom variables relations
     sub_module  => 'orderitems',
     cvars_alias => 1,
     overloads   => {
-      parts_id    => 'SL::DB::Part',
+      parts_id    => {
+        class => 'SL::DB::Part',
+        module => 'IC',
+      }
     }
   );
 
@@ -218,6 +265,11 @@ Secondary classes may currently not have cvars of their own.
 This is a Rose::DB::Object::Relationship accessor, generated for cvars. Use it
 like any other OneToMany relationship.
 
+Note that unlike L</cvars_by_config> this accessor only returns
+variables that have already been created for this object. No variables
+will be autovivified for configs for which no variable has been
+created yet.
+
 =item C<cvars [ CUSTOM_VARIABLES ]>
 
 Alias to C<custom_variables>. Will only be installed if C<cvars_alias> was
@@ -262,6 +314,7 @@ vivified with the same rules as in C<cvars_by_config>.
 
 =head1 AUTHOR
 
-Sven Schöling E<lt>s.schoeling@linet-services.deE<gt>
+Sven Schöling E<lt>s.schoeling@linet-services.deE<gt>,
+Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
 
 =cut