]> wagnertech.de Git - mfinanz.git/blobdiff - SL/DB/Helper/ActsAsList.pm
Refactoring: Parameterredesign SL::Controller::Base::render und SL::Presenter::render
[mfinanz.git] / SL / DB / Helper / ActsAsList.pm
index ade8fdc108b18f8b813811e67189bb683aa000f4..ce927bba41390be1149bf9f041c80215846a2246 100644 (file)
@@ -3,7 +3,7 @@ package SL::DB::Helper::ActsAsList;
 use strict;
 
 use parent qw(Exporter);
-our @EXPORT = qw(move_position_up move_position_down);
+our @EXPORT = qw(move_position_up move_position_down reorder_list);
 
 use Carp;
 
@@ -33,15 +33,38 @@ sub move_position_down {
   do_move($self, 'down');
 }
 
+sub reorder_list {
+  my ($class_or_self, @ids) = @_;
+
+  return 1 unless @ids;
+
+  my $self   = ref($class_or_self) ? $class_or_self : $class_or_self->new;
+  my $column = column_name($self);
+  my $result = $self->db->do_transaction(sub {
+    my $query = qq|UPDATE | . $self->meta->table . qq| SET ${column} = ? WHERE id = ?|;
+    my $sth   = $self->db->dbh->prepare($query) || die $self->db->dbh->errstr;
+
+    foreach my $new_position (1 .. scalar(@ids)) {
+      $sth->execute($new_position, $ids[$new_position - 1]) || die $sth->errstr;
+    }
+
+    $sth->finish;
+  });
+
+  return $result;
+}
+
 #
 # Helper functions
 #
 
 sub set_position {
   my ($self) = @_;
-  if (!defined $self->position) {
-    my $max_position = $self->db->dbh->selectrow_arrayref(qq|SELECT COALESCE(max(position), 0) FROM | . $self->meta->table)->[0];
-    $self->position($max_position + 1);
+  my $column = column_name($self);
+
+  if (!defined $self->$column) {
+    my $max_position = $self->db->dbh->selectrow_arrayref(qq|SELECT COALESCE(max(${column}), 0) FROM | . $self->meta->table)->[0];
+    $self->$column($max_position + 1);
   }
 
   return 1;
@@ -49,11 +72,12 @@ sub set_position {
 
 sub remove_position {
   my ($self) = @_;
+  my $column = column_name($self);
 
   $self->load;
-  if (defined $self->position) {
-    $self->_get_manager_class->update_all(set   => { position => \'position - 1' },
-                                          where => [ position => { gt => $self->position } ]);
+  if (defined $self->$column) {
+    $self->_get_manager_class->update_all(set   => { $column => \"${column} - 1" },
+                                          where => [ $column => { gt => $self->$column } ]);
   }
 
   return 1;
@@ -61,19 +85,25 @@ sub remove_position {
 
 sub do_move {
   my ($self, $direction) = @_;
+  my $column             = column_name($self);
 
   croak "Object has not been saved yet" unless $self->id;
-  croak "No position set yet"           unless defined $self->position;
+  croak "No position set yet"           unless defined $self->$column;
 
   my ($comp_sql, $comp_rdbo, $min_max, $plus_minus) = $direction eq 'up' ? ('<', 'ge', 'max', '+') : ('>', 'le', 'min', '-');
 
-  my $new_position = $self->db->dbh->selectrow_arrayref(qq|SELECT ${min_max}(position) FROM | . $self->meta->table . qq| WHERE position ${comp_sql} | . $self->position)->[0];
+  my $new_position = $self->db->dbh->selectrow_arrayref(qq|SELECT ${min_max}(${column}) FROM | . $self->meta->table . qq| WHERE ${column} ${comp_sql} | . $self->$column)->[0];
 
   return undef unless defined $new_position;
 
-  $self->_get_manager_class->update_all(set   => { position => $self->position },
-                                        where => [ position => $new_position ]);
-  $self->update_attributes(position => $new_position);
+  $self->_get_manager_class->update_all(set   => { $column => $self->$column },
+                                        where => [ $column => $new_position ]);
+  $self->update_attributes($column => $new_position);
+}
+
+sub column_name {
+  my ($self) = @_;
+  return $self->can('sortkey') ? 'sortkey' : 'position';
 }
 
 1;
@@ -85,7 +115,8 @@ __END__
 
 =head1 NAME
 
-SL::DB::Helper::ActsAsList - Mixin for managing ordered items by a column I<position>
+SL::DB::Helper::ActsAsList - Mixin for managing ordered items by a
+column I<position> or I<sortkey>
 
 =head1 SYNOPSIS
 
@@ -107,9 +138,10 @@ SL::DB::Helper::ActsAsList - Mixin for managing ordered items by a column I<posi
   $obj->delete
 
 This mixin assumes that the mixing package's table contains a column
-called C<position>. This column is set automatically upon saving the
-object if it hasn't been set already. If it hasn't then it will be set
-to the maximum position used in the table plus one.
+called C<position> or C<sortkey> (for legacy tables). This column is
+set automatically upon saving the object if it hasn't been set
+already. If it hasn't then it will be set to the maximum position used
+in the table plus one.
 
 When the object is deleted all positions greater than the object's old
 position are decreased by one.
@@ -128,6 +160,22 @@ regarding their sort order by exchanging their C<position> values.
 Swaps the object with the object one step below the current one
 regarding their sort order by exchanging their C<position> values.
 
+=item C<reorder_list @ids>
+
+Re-orders the objects given in C<@ids> by their position in C<@ids> by
+updating all of their positional columns. Each element in
+C<@positions> must be the ID of an object. The new position is the
+ID's index inside C<@ids> plus one (meaning the first element's new
+position will be 1 and not 0).
+
+This works by executing SQL "UPDATE" statements directly.
+
+Returns the result of the whole transaction (trueish in case of
+success).
+
+This method can be called both as a class method or an instance
+method.
+
 =back
 
 =head1 BUGS