1 package SL::DB::Helper::ActsAsList;
5 use parent qw(Exporter);
6 our @EXPORT = qw(move_position_up move_position_down);
11 my ($class, @params) = @_;
12 my $importing = caller();
14 $importing->before_save( sub { SL::DB::Helper::ActsAsList::set_position(@_) });
15 $importing->before_delete(sub { SL::DB::Helper::ActsAsList::remove_position(@_) });
17 # Use 'goto' so that Exporter knows which module to import into via
19 goto &Exporter::import;
26 sub move_position_up {
31 sub move_position_down {
33 do_move($self, 'down');
42 if (!defined $self->position) {
43 my $max_position = $self->db->dbh->selectrow_arrayref(qq|SELECT COALESCE(max(position), 0) FROM | . $self->meta->table)->[0];
44 $self->position($max_position + 1);
54 if (defined $self->position) {
55 $self->_get_manager_class->update_all(set => { position => \'position - 1' },
56 where => [ position => { gt => $self->position } ]);
63 my ($self, $direction) = @_;
65 croak "Object has not been saved yet" unless $self->id;
66 croak "No position set yet" unless defined $self->position;
68 my ($comp_sql, $comp_rdbo, $min_max, $plus_minus) = $direction eq 'up' ? ('<', 'ge', 'max', '+') : ('>', 'le', 'min', '-');
70 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];
72 return undef unless defined $new_position;
74 $self->_get_manager_class->update_all(set => { position => $self->position },
75 where => [ position => $new_position ]);
76 $self->update_attributes(position => $new_position);
88 SL::DB::Helper::ActsAsList - Mixin for managing ordered items by a column I<position>
92 package SL::DB::SomeObject;
93 use SL::DB::Helper::ActsAsList;
95 package SL::Controller::SomeController;
97 # Assign a position automatically
98 $obj = SL::DB::SomeObject->new(description => 'bla');
101 # Move items up and down
102 $obj = SL::DB::SomeOBject->new(id => 1)->load;
103 $obj->move_position_up;
104 $obj->move_position_down;
106 # Adjust all remaining positions automatically
109 This mixin assumes that the mixing package's table contains a column
110 called C<position>. This column is set automatically upon saving the
111 object if it hasn't been set already. If it hasn't then it will be set
112 to the maximum position used in the table plus one.
114 When the object is deleted all positions greater than the object's old
115 position are decreased by one.
121 =item C<move_position_up>
123 Swaps the object with the object one step above the current one
124 regarding their sort order by exchanging their C<position> values.
126 =item C<move_position_down>
128 Swaps the object with the object one step below the current one
129 regarding their sort order by exchanging their C<position> values.
139 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>