1DBIx::Class::Ordered(3)User Contributed Perl DocumentatioDnBIx::Class::Ordered(3)
2
3
4

NAME

6       DBIx::Class::Ordered - Modify the position of objects in an ordered
7       list.
8

SYNOPSIS

10       Create a table for your ordered data.
11
12         CREATE TABLE items (
13           item_id INTEGER PRIMARY KEY AUTOINCREMENT,
14           name TEXT NOT NULL,
15           position INTEGER NOT NULL
16         );
17
18       Optionally, add one or more columns to specify groupings, allowing you
19       to maintain independent ordered lists within one table:
20
21         CREATE TABLE items (
22           item_id INTEGER PRIMARY KEY AUTOINCREMENT,
23           name TEXT NOT NULL,
24           position INTEGER NOT NULL,
25           group_id INTEGER NOT NULL
26         );
27
28       Or even
29
30         CREATE TABLE items (
31           item_id INTEGER PRIMARY KEY AUTOINCREMENT,
32           name TEXT NOT NULL,
33           position INTEGER NOT NULL,
34           group_id INTEGER NOT NULL,
35           other_group_id INTEGER NOT NULL
36         );
37
38       In your Schema or DB class add "Ordered" to the top of the component
39       list.
40
41         __PACKAGE__->load_components(qw( Ordered ... ));
42
43       Specify the column that stores the position number for each row.
44
45         package My::Item;
46         __PACKAGE__->position_column('position');
47
48       If you are using one grouping column, specify it as follows:
49
50         __PACKAGE__->grouping_column('group_id');
51
52       Or if you have multiple grouping columns:
53
54         __PACKAGE__->grouping_column(['group_id', 'other_group_id']);
55
56       That's it, now you can change the position of your objects.
57
58         #!/use/bin/perl
59         use My::Item;
60
61         my $item = My::Item->create({ name=>'Matt S. Trout' });
62         # If using grouping_column:
63         my $item = My::Item->create({ name=>'Matt S. Trout', group_id=>1 });
64
65         my $rs = $item->siblings();
66         my @siblings = $item->siblings();
67
68         my $sibling;
69         $sibling = $item->first_sibling();
70         $sibling = $item->last_sibling();
71         $sibling = $item->previous_sibling();
72         $sibling = $item->next_sibling();
73
74         $item->move_previous();
75         $item->move_next();
76         $item->move_first();
77         $item->move_last();
78         $item->move_to( $position );
79         $item->move_to_group( 'groupname' );
80         $item->move_to_group( 'groupname', $position );
81         $item->move_to_group( {group_id=>'groupname', 'other_group_id=>'othergroupname'} );
82         $item->move_to_group( {group_id=>'groupname', 'other_group_id=>'othergroupname'}, $position );
83

DESCRIPTION

85       This module provides a simple interface for modifying the ordered
86       position of DBIx::Class objects.
87

AUTO UPDATE

89       All of the move_* methods automatically update the rows involved in the
90       query.  This is not configurable and is due to the fact that if you
91       move a record it always causes other records in the list to be updated.
92

METHODS

94   position_column
95         __PACKAGE__->position_column('position');
96
97       Sets and retrieves the name of the column that stores the positional
98       value of each record.  Defaults to "position".
99
100   grouping_column
101         __PACKAGE__->grouping_column('group_id');
102
103       This method specifies a column to limit all queries in this module by.
104       This effectively allows you to have multiple ordered lists within the
105       same table.
106
107   null_position_value
108         __PACKAGE__->null_position_value(undef);
109
110       This method specifies a value of "position_column" which would never be
111       assigned to a row during normal operation. When a row is moved, its
112       position is set to this value temporarily, so that any unique
113       constraints can not be violated. This value defaults to 0, which should
114       work for all cases except when your positions do indeed start from 0.
115
116   siblings
117         my $rs = $item->siblings();
118         my @siblings = $item->siblings();
119
120       Returns an ordered resultset of all other objects in the same group
121       excluding the one you called it on.
122
123       The ordering is a backwards-compatibility artifact - if you need a
124       resultset with no ordering applied use "_siblings"
125
126   previous_siblings
127         my $prev_rs = $item->previous_siblings();
128         my @prev_siblings = $item->previous_siblings();
129
130       Returns a resultset of all objects in the same group positioned before
131       the object on which this method was called.
132
133   next_siblings
134         my $next_rs = $item->next_siblings();
135         my @next_siblings = $item->next_siblings();
136
137       Returns a resultset of all objects in the same group positioned after
138       the object on which this method was called.
139
140   previous_sibling
141         my $sibling = $item->previous_sibling();
142
143       Returns the sibling that resides one position back.  Returns 0 if the
144       current object is the first one.
145
146   first_sibling
147         my $sibling = $item->first_sibling();
148
149       Returns the first sibling object, or 0 if the first sibling is this
150       sibling.
151
152   next_sibling
153         my $sibling = $item->next_sibling();
154
155       Returns the sibling that resides one position forward. Returns 0 if the
156       current object is the last one.
157
158   last_sibling
159         my $sibling = $item->last_sibling();
160
161       Returns the last sibling, or 0 if the last sibling is this sibling.
162
163   move_previous
164         $item->move_previous();
165
166       Swaps position with the sibling in the position previous in the list.
167       Returns 1 on success, and 0 if the object is already the first one.
168
169   move_next
170         $item->move_next();
171
172       Swaps position with the sibling in the next position in the list.
173       Returns 1 on success, and 0 if the object is already the last in the
174       list.
175
176   move_first
177         $item->move_first();
178
179       Moves the object to the first position in the list.  Returns 1 on
180       success, and 0 if the object is already the first.
181
182   move_last
183         $item->move_last();
184
185       Moves the object to the last position in the list.  Returns 1 on
186       success, and 0 if the object is already the last one.
187
188   move_to
189         $item->move_to( $position );
190
191       Moves the object to the specified position.  Returns 1 on success, and
192       0 if the object is already at the specified position.
193
194   move_to_group
195         $item->move_to_group( $group, $position );
196
197       Moves the object to the specified position of the specified group, or
198       to the end of the group if $position is undef.  1 is returned on
199       success, and 0 is returned if the object is already at the specified
200       position of the specified group.
201
202       $group may be specified as a single scalar if only one grouping column
203       is in use, or as a hashref of column => value pairs if multiple
204       grouping columns are in use.
205
206   insert
207       Overrides the DBIC insert() method by providing a default position
208       number.  The default will be the number of rows in the table +1, thus
209       positioning the new record at the last position.
210
211   update
212       Overrides the DBIC update() method by checking for a change to the
213       position and/or group columns.  Movement within a group or to another
214       group is handled by repositioning the appropriate siblings.  Position
215       defaults to the end of a new group if it has been changed to undef.
216
217   delete
218       Overrides the DBIC delete() method by first moving the object to the
219       last position, then deleting it, thus ensuring the integrity of the
220       positions.
221

METHODS FOR EXTENDING ORDERED

223       You would want to override the methods below if you use sparse (non-
224       linear) or non-numeric position values. This can be useful if you are
225       working with preexisting non-normalised position data, or if you need
226       to work with materialized path columns.
227
228   _position_from_value
229         my $num_pos = $item->_position_from_value ( $pos_value )
230
231       Returns the absolute numeric position of an object with a position
232       value set to $pos_value. By default simply returns $pos_value.
233
234   _position_value
235         my $pos_value = $item->_position_value ( $pos )
236
237       Returns the value of "position_column" of the object at numeric
238       position $pos. By default simply returns $pos.
239
240   _initial_position_value
241         __PACKAGE__->_initial_position_value(0);
242
243       This method specifies a value of "position_column" which is assigned to
244       the first inserted element of a group, if no value was supplied at
245       insertion time. All subsequent values are derived from this one by
246       "_next_position_value" below. Defaults to 1.
247
248   _next_position_value
249         my $new_value = $item->_next_position_value ( $position_value )
250
251       Returns a position value that would be considered "next" with regards
252       to $position_value. Can be pretty much anything, given that
253       "$position_value < $new_value" where "<" is the SQL comparison operator
254       (usually works fine on strings). The default method expects
255       $position_value to be numeric, and returns "$position_value + 1"
256
257   _shift_siblings
258         $item->_shift_siblings ($direction, @between)
259
260       Shifts all siblings with positions values in the range @between
261       (inclusive) by one position as specified by $direction (left if < 0,
262        right if > 0). By default simply increments/decrements each
263       position_column value by 1, doing so in a way as to not violate any
264       existing constraints.
265
266       Note that if you override this method and have unique constraints
267       including the position_column the shift is not a trivial task.  Refer
268       to the implementation source of the default method for more
269       information.
270

PRIVATE METHODS

272       These methods are used internally.  You should never have the need to
273       use them.
274
275   _group_rs
276       This method returns a resultset containing all members of the row group
277       (including the row itself).
278
279   _siblings
280       Returns an unordered resultset of all objects in the same group
281       excluding the object you called this method on.
282
283   _position
284         my $num_pos = $item->_position;
285
286       Returns the absolute numeric position of the current object, with the
287       first object being at position 1, its sibling at position 2 and so on.
288
289   _grouping_clause
290       This method returns one or more name=>value pairs for limiting a search
291       by the grouping column(s).  If the grouping column is not defined then
292       this will return an empty list.
293
294   _get_grouping_columns
295       Returns a list of the column names used for grouping, regardless of
296       whether they were specified as an arrayref or a single string, and
297       returns () if there is no grouping.
298
299   _is_in_group
300           $item->_is_in_group( {user => 'fred', list => 'work'} )
301
302       Returns true if the object is in the group represented by hashref
303       $other
304
305   _ordered_internal_update
306       This is a short-circuited method, that is used internally by this
307       module to update positioning values in isolation (i.e. without
308       triggering any of the positioning integrity code).
309
310       Some day you might get confronted by datasets that have ambiguous
311       positioning data (e.g. duplicate position values within the same group,
312       in a table without unique constraints). When manually fixing such data
313       keep in mind that you can not invoke "update" in DBIx::Class::Row like
314       you normally would, as it will get confused by the wrong data before
315       having a chance to update the ill-defined row. If you really know what
316       you are doing use this method which bypasses any hooks introduced by
317       this module.
318

CAVEATS

320   Race Condition on Insert
321       If a position is not specified for an insert than a position will be
322       chosen based either on "_initial_position_value" or
323       "_next_position_value", depending if there are already some items in
324       the current group. The space of time between the necessary selects and
325       insert introduces a race condition.  Having unique constraints on your
326       position/group columns, and using transactions (see "txn_do" in
327       DBIx::Class::Storage) will prevent such race conditions going
328       undetected.
329
330   Multiple Moves
331       Be careful when issuing move_* methods to multiple objects.  If you've
332       pre-loaded the objects then when you move one of the objects the
333       position of the other object will not reflect their new value until you
334       reload them from the database - see "discard_changes" in
335       DBIx::Class::Row.
336
337       There are times when you will want to move objects as groups, such as
338       changing the parent of several objects at once - this directly
339       conflicts with this problem.  One solution is for us to write a
340       ResultSet class that supports a parent() method, for example.  Another
341       solution is to somehow automagically modify the objects that exist in
342       the current object's result set to have the new position value.
343
344   Default Values
345       Using a database defined default_value on one of your group columns
346       could result in the position not being assigned correctly.
347

AUTHOR

349        Original code framework
350          Aran Deltac <bluefeet@cpan.org>
351
352        Constraints support and code generalisation
353          Peter Rabbitson <ribasushi@cpan.org>
354

LICENSE

356       You may distribute this code under the same terms as Perl itself.
357
358
359
360perl v5.12.0                      2010-05-12           DBIx::Class::Ordered(3)
Impressum