X-Git-Url: http://wagnertech.de/git?a=blobdiff_plain;f=SL%2FDB%2FHelper%2FActsAsList.pm;h=ee49f4aed2251e62d61d3c10e697e886c74ab98b;hb=0ff17226240249b036073f696ecc6e15017f98be;hp=86ee2ec95963d482557d7b0c9a901f1d5ce36168;hpb=f12b3596807e5a46c6ed3e86c43e01492d2dc6c1;p=kivitendo-erp.git diff --git a/SL/DB/Helper/ActsAsList.pm b/SL/DB/Helper/ActsAsList.pm index 86ee2ec95..ee49f4aed 100644 --- a/SL/DB/Helper/ActsAsList.pm +++ b/SL/DB/Helper/ActsAsList.pm @@ -3,7 +3,8 @@ package SL::DB::Helper::ActsAsList; use strict; use parent qw(Exporter); -our @EXPORT = qw(move_position_up move_position_down add_to_list remove_from_list reorder_list configure_acts_as_list); +our @EXPORT = qw(move_position_up move_position_down add_to_list remove_from_list reorder_list configure_acts_as_list + get_previous_in_list get_next_in_list get_full_list); use Carp; @@ -13,12 +14,13 @@ sub import { my ($class, @params) = @_; my $importing = caller(); + configure_acts_as_list($importing, @params); + $importing->before_save( sub { SL::DB::Helper::ActsAsList::set_position(@_) }); $importing->before_delete(sub { SL::DB::Helper::ActsAsList::remove_position(@_) }); - # Use 'goto' so that Exporter knows which module to import into via - # 'caller()'. - goto &Exporter::import; + # Don't 'goto' to Exporters import, it would try to parse @params + __PACKAGE__->export_to_level(1, $class, @EXPORT); } # @@ -38,10 +40,10 @@ sub move_position_down { sub remove_from_list { my ($self) = @_; - my $worker = sub { + return $self->db->with_transaction(sub { remove_position($self); - # Set to NULL manually because $self->update_attributes() would + # Set to -1 manually because $self->update_attributes() would # trigger the before_save() hook from this very plugin assigning a # number at the end of the list again. my $table = $self->meta->table; @@ -49,14 +51,12 @@ sub remove_from_list { my $primary_key_col = ($self->meta->primary_key)[0]; my $sql = <db->dbh->do($sql, undef, $self->$primary_key_col); $self->$column(undef); - }; - - return $self->db->in_transaction ? $worker->() : $self->db->do_transaction($worker); + }); } sub add_to_list { @@ -64,6 +64,10 @@ sub add_to_list { croak "Invalid parameter 'position'" unless ($params{position} || '') =~ m/^ (?: before | after | first | last ) $/x; + my $column = column_name($self); + + $self->remove_from_list if ($self->$column // -1) != -1; + if ($params{position} eq 'last') { set_position($self); $self->save; @@ -72,7 +76,6 @@ sub add_to_list { my $table = $self->meta->table; my $primary_key_col = ($self->meta->primary_key)[0]; - my $column = column_name($self); my ($group_by, @values) = get_group_by_where($self); $group_by = " AND ${group_by}" if $group_by; my $new_position; @@ -104,12 +107,30 @@ sub add_to_list { ${group_by} SQL - my $worker = sub { + return $self->db->with_transaction(sub { $self->db->dbh->do($query, undef, $new_position - 1, @values); $self->update_attributes($column => $new_position); - }; + }); +} + +sub get_next_in_list { + my ($self) = @_; + return get_previous_or_next($self, 'next'); +} + +sub get_previous_in_list { + my ($self) = @_; + return get_previous_or_next($self, 'previous'); +} + +sub get_full_list { + my ($self) = @_; + + my $group_by = get_spec(ref $self, 'group_by') || []; + $group_by = [ $group_by ] if $group_by && !ref $group_by; + my @where = map { ($_ => $self->$_) } @{ $group_by }; - return $self->db->in_transaction ? $worker->() : $self->db->do_transaction($worker); + return $self->_get_manager_class->get_all(where => \@where, sort_by => column_name($self) . ' ASC'); } sub reorder_list { @@ -119,7 +140,7 @@ sub reorder_list { 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 $result = $self->db->with_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; @@ -128,6 +149,8 @@ sub reorder_list { } $sth->finish; + + 1; }); return $result; @@ -165,16 +188,18 @@ sub get_group_by_where { sub set_position { my ($self) = @_; my $column = column_name($self); + my $value = $self->$column; - return 1 if defined $self->$column; + return 1 if defined($value) && ($value != -1); my $table = $self->meta->table; my ($group_by, @values) = get_group_by_where($self); - my $where = $group_by ? " WHERE ${group_by}" : ''; + $group_by = " AND ${group_by}" if $group_by; my $sql = < -1) + ${group_by} SQL my $max_position = $self->db->dbh->selectrow_arrayref($sql, undef, @values)->[0]; @@ -188,10 +213,10 @@ sub remove_position { my $column = column_name($self); $self->load; - return 1 unless defined $self->$column; + my $value = $self->$column; + return 1 unless defined($value) && ($value != -1); my $table = $self->meta->table; - my $value = $self->$column; my ($group_by, @values) = get_group_by_where($self); $group_by = ' AND ' . $group_by if $group_by; my $sql = <id; - croak "No position set yet" unless defined $self->$column; + + my $column = column_name($self); + my $old_position = $self->$column; + croak "No position set yet" unless defined($old_position) && ($old_position != -1); my $table = $self->meta->table; - my $old_position = $self->$column; my ($comp_sel, $comp_upd, $min_max, $plus_minus) = $direction eq 'up' ? ('<', '>=', 'MAX', '+') : ('>', '<=', 'MIN', '-'); my ($group_by, @values) = get_group_by_where($self); $group_by = ' AND ' . $group_by if $group_by; my $sql = < -1) + AND (${column} ${comp_sel} ?) ${group_by} SQL @@ -241,6 +268,30 @@ SQL $self->update_attributes($column => $new_position); } +sub get_previous_or_next { + my ($self, $direction) = @_; + + my $asc_desc = $direction eq 'next' ? 'ASC' : 'DESC'; + my $comparator = $direction eq 'next' ? '>' : '<'; + my $table = $self->meta->table; + my $column = column_name($self); + my $primary_key_col = ($self->meta->primary_key)[0]; + my ($group_by, @values) = get_group_by_where($self); + $group_by = " AND ${group_by}" if $group_by; + my $sql = <db->dbh->selectrow_arrayref($sql, undef, $self->$column, @values) || [])->[0]; + + return $id ? $self->_get_manager_class->find_by(id => $id) : undef; +} + sub column_name { my ($self) = @_; my $column = get_spec(ref $self, 'column_name'); @@ -270,7 +321,7 @@ column =head1 SYNOPSIS package SL::DB::SomeObject; - use SL::DB::Helper::ActsAsList; + use SL::DB::Helper::ActsAsList [ PARAMS ]; package SL::Controller::SomeController; ... @@ -295,7 +346,8 @@ in the table plus one. When the object is deleted all positions greater than the object's old position are decreased by one. -The column name to use can be configured via L. +C will be given to L and can be used to +set the column name. =head1 CLASS FUNCTIONS @@ -303,8 +355,8 @@ The column name to use can be configured via L. =item C -Configures the mixin's behaviour. C<%params> can contain the following -values: +Configures the mixin's behaviour. Will get called automatically with the +include parameters. C<%params> can contain the following values: =over 2 @@ -360,14 +412,33 @@ one. The current item will then be inserted either before or after the referenced item by shifting all the appropriate item positions up by one. +If C<$self>'s positional column is already set when this function is +called then L will be called first before anything +else is done. + After this function C<$self>'s positional column has been set and saved to the database. =item C -Sets this items positional column to C, saves it and moves all +Sets this items positional column to C<-1>, saves it and moves all following items up by 1. +=item C + +Fetches the previous item in the list. Returns C if C<$self> is +already the first one. + +=item C + +Fetches the next item in the list. Returns C if C<$self> is +already the last one. + +=item C + +Fetches all items in the same list as C<$self> and returns them as an +array reference. + =item C Re-orders the objects given in C<@ids> by their position in C<@ids> by