]> wagnertech.de Git - kivitendo-erp.git/blob - SL/DB/Helpers/Sorted.pm
Helfer für Manager für das Sortieren von Datenbankergebnissen
[kivitendo-erp.git] / SL / DB / Helpers / Sorted.pm
1 package SL::DB::Helpers::Sorted;
2
3 use strict;
4
5 require Exporter;
6 our @ISA    = qw(Exporter);
7 our @EXPORT = qw(get_all_sorted make_sort_string);
8
9 my %sort_spec;
10
11 sub make_sort_string {
12   my ($class, %params) = @_;
13
14   %sort_spec           = $class->_sort_spec unless %sort_spec;
15
16   my $sort_dir         = defined($params{sort_dir}) ? $params{sort_dir} * 1 : $sort_spec{default}->[1];
17   my $sort_dir_str     = $sort_dir ? 'ASC' : 'DESC';
18
19   my $sort_by          = $params{sort_by};
20   $sort_by             = $sort_spec{default}->[0] unless $sort_spec{columns}->{$sort_by};
21
22   my $nulls_str        = '';
23   if ($sort_spec{nulls}) {
24     $nulls_str = ref($sort_spec{nulls}) ? ($sort_spec{nulls}->{$sort_by} || $sort_spec{nulls}->{default}) : $sort_spec{nulls};
25     $nulls_str = " NULLS ${nulls_str}" if $nulls_str;
26   }
27
28   my $sort_by_str = $sort_spec{columns}->{$sort_by};
29   $sort_by_str    = [ $sort_by_str ] unless ref($sort_by_str) eq 'ARRAY';
30   $sort_by_str    = join(', ', map { "${_} ${sort_dir_str}${nulls_str}" } @{ $sort_by_str });
31
32   return wantarray ? ($sort_by, $sort_dir, $sort_by_str) : $sort_by_str;
33 }
34
35 sub get_all_sorted {
36   my ($class, %params) = @_;
37   my $sort_str         = $class->make_sort_string(sort_by => delete($params{sort_by}), sort_dir => delete($params{sort_dir}));
38
39   return $class->get_all(sort_by => $sort_str, %params);
40 }
41
42 1;
43
44 __END__
45
46 =encoding utf8
47
48 =head1 NAME
49
50 SL::DB::Helpers::Sorted - Mixin for a manager class that handles
51 sorting of database records
52
53 =head1 SYNOPSIS
54
55   package SL::DB::Manager::Message;
56
57   use SL::DB::Helpers::Sorted;
58
59   sub _sort_spec {
60     return ( columns => { recipient_id => [ 'CASE
61                                              WHEN recipient_group_id IS NULL THEN lower(recipient.name)
62                                              ELSE                                 lower(recipient_group.name)
63                                              END',                                      ],
64                           sender_id    => [ 'lower(sender.name)',                       ],
65                           created_at   => [ 'created_at',                               ],
66                           subject      => [ 'lower(subject)',                           ],
67                           status       => [ 'NOT COALESCE(unread, FALSE)', 'created_at' ],
68                         },
69              default => [ 'status', 1 ],
70              nulls   => { default => 'LAST',
71                           subject => 'FIRST',
72                         }
73            );
74   }
75
76   package SL::Controller::Message;
77
78   sub action_list {
79     my $messages = SL::DB::Manager::Message->get_all_sorted(sort_by  => $::form->{sort_by},
80                                                             sort_dir => $::form->{sort_dir});
81   }
82
83 =head1 CLASS FUNCTIONS
84
85 =over 4
86
87 =item C<make_sort_string %params>
88
89 Evaluates C<$params{sort_by}> and C<$params{sort_dir}> and returns an
90 SQL string suitable for sorting. The package this package is mixed
91 into has to provide a method L</_sort_spec> that returns a hash whose
92 structure is explained below. That hash is authoritive in which
93 columns may be sorted, which column to sort by by default and how to
94 handle C<NULL> values.
95
96 Returns the SQL string in scalar context. In array context it returns
97 three values: the actual column it sorts by (suitable for another call
98 to L</make_sort_string>), the actual sort direction (either 0 or 1)
99 and the SQL string.
100
101 =item C<get_all_sorted %params>
102
103 Returns C<< $class->get_all >> with C<sort_by> set to the value
104 returned by c<< $class->make_sort_string(%params) >>.
105
106 =back
107
108 =head1 CLASS FUNCTIONS PROVIDED BY THE MIXING PACKAGE
109
110 =over 4
111
112 =item C<_sort_spec>
113
114 This method is actually not part of this package but must be provided
115 by the package this helper is mixed into.
116
117 Returns a has with the following keys:
118
119 =over 2
120
121 =item C<default>
122
123 A two-element array containing the name and direction by which to sort
124 in default cases. Example:
125
126   default => [ 'name', 1 ],
127
128 =item C<columns>
129
130 A hash reference. Its keys are column names, and its values are SQL
131 strings by which to sort. Example:
132
133   columns => { transaction_description => 'oe.transaction_description',
134                customer_name           => 'lower(customer.name)',
135              },
136
137 If sorting by a column is requested that is not a key in this hash
138 then the default column name will be used.
139
140 The value can be either a scalar or an array reference. If it's the
141 latter then both the sort direction as well as the null handling will
142 be appended to each of its members.
143
144 =item C<nulls>
145
146 Either a scalar or a hash reference determining where C<NULL> values
147 will be sorted. If undefined then the decision is left to the
148 database.
149
150 If it is a scalar then all the same value will be used for all
151 classes. The value is either C<FIRST> or C<LAST>.
152
153 If it is a hash reference then its keys are column names (not SQL
154 names). The values are either C<FIRST> or C<LAST>. If a column name is
155 not found in this hash then the special keu C<default> will be looked
156 up and used if it is found.
157
158 Example:
159
160   nulls => { transaction_description => 'FIRST',
161              customer_name           => 'FIRST',
162              default                 => 'LAST',
163            },
164
165 =back
166
167 =back
168
169 =head1 BUGS
170
171 Nothing here yet.
172
173 =head1 AUTHOR
174
175 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
176
177 =cut