Refactoring
[kivitendo-erp.git] / SL / Clipboard / Base.pm
1 package SL::Clipboard::Base;
2
3 use strict;
4
5 use parent qw(Rose::Object);
6
7 use Rose::Object::MakeMethods::Generic (
8   'scalar --get_set_init' => [ qw(content timestamp) ],
9 );
10
11 use Rose::DB::Object::Helpers ();
12
13 sub init_timestamp { die "'timestamp' property not set"; }
14 sub init_content   { die "'content' property not set";   }
15
16 sub type {
17   my ($self_or_class) = @_;
18   return (split m/::/, ref($self_or_class) ? ref($self_or_class) : $self_or_class)[-1];
19 }
20
21 sub reload_object {
22   my ($self, $object) = @_;
23
24   return ref($object)->new(map { $_ => $object->$_ } $object->meta->primary_key)->load;
25 }
26
27 sub as_tree {
28   my ($self, $object, %params) = @_;
29
30   my $tree = Rose::DB::Object::Helpers::as_tree($object, %params);
31   $self->_fix_tree($tree, $object);
32   return $tree;
33 }
34
35 sub to_object {
36   my ($self) = @_;
37   my $object = Rose::DB::Object::Helpers::new_from_tree("SL::DB::" . $self->type, $self->content);
38
39   # Reset primary key columns and itime/mtime if the class supports it.
40   foreach ($object->meta->primary_key, 'itime', 'mtime') {
41     $object->$_(undef) if $object->can($_);
42   }
43
44   # Let sub classes fix the objects further.
45   $self->_fix_object($object);
46   return $object;
47 }
48
49 sub dump {
50   my ($self, $object) = @_;
51   return $self->as_tree($self->reload_object($object), max_depth => 1);
52 }
53
54 sub describe {
55   die "'describe' method not overwritten by derived class";
56 }
57
58 sub _fix_object {
59   my ($self, $object) = @_;
60   # To be overwritten by child classes.
61 }
62
63 sub _fix_tree {
64   my ($self, $tree, $object) = @_;
65
66   # Delete primary key columns and itime/mtime if the class supports it.
67   foreach ($object->meta->primary_key, 'itime', 'mtime') {
68     delete $tree->{$_} if $object->can($_);
69   }
70 }
71
72 1;
73 __END__
74
75 =pod
76
77 =encoding utf8
78
79 =head1 NAME
80
81 SL::Clipboard::Base - Base class for clipboard specialization classes
82
83 =head1 SYNOPSIS
84
85 See the synopsis of L<SL::Clipboard>.
86
87 =head1 OVERVIEW
88
89 This is a base class providing a lot of utility and
90 defaults. Sub-classes must overwrite at least the function
91 L</describe> but can overwrite others as well.
92
93 Writing a specialized sub-class for a database type involves
94 overwriting one or more functions. These are:
95
96 =over 4
97
98 =item * C<describe>
99
100 Must be overwritten. Returns a human-readable description of the
101 content. Should only be one line.
102
103 =item * C<dump>
104
105 Optional. Overwrite if sub-class needs to dump more/less than the
106 implementation in this class dumps.
107
108 =item * C<_fix_object>
109
110 Optional. Overwrite if re-created Rose::DB::Object instances must be
111 cleaned further before they're returned to the caller.
112
113 =item * C<_fix_tree>
114
115 Optional. Overwrite if the tree created during a copy operation of a
116 Rose::DB::Object instance must be cleaned further before it's stored.
117
118 =back
119
120 You don't have to or should not overwrite the other functions:
121
122 =over 4
123
124 =item * C<as_tree>
125
126 =item * C<reload_object>
127
128 =item * C<to_object>
129
130 =item * C<type>
131
132 =back
133
134 Don't forget to C<use> the specialized module here in Base!
135
136 =head1 FUNCTIONS
137
138 =over 4
139
140 =item C<as_tree $object, %params>
141
142 A convenience function calling L<Rose::DB::Object::Helpers/as_tree>
143 with C<$object> and C<%params> as parameters. Returns a hash/array
144 reference tree of the function.
145
146 Don't overwrite this function in sub-classes. Overwrite L</dump>
147 instead.
148
149 =item C<describe>
150
151 Returns a human-readable description of the content. This should only
152 be a single line without any markup.
153
154 Sub-classes must overwrite this function.
155
156 =item C<dump $object>
157
158 Dumps the object as a hash/array tree and returns it by calling
159 L<Rose::DB::Object::Helpers/as_tree>. The default implementation
160 reloads the object first by calling L</reload_object>. It also only
161 dumps the object itself, not any of the relationships, by calling
162 C<as_tree> with the parameter C<max_depth =E<gt> 1>.
163
164 Overwrite this in a sub-class if you need to dump more or differently
165 (see L<SL::Clipboard::RequirementSpecItem> for an example).
166
167 =item C<reload_object $object>
168
169 Reloads C<$object> from the database and returns a new instance. Can
170 be useful for sanitizing the object given to L</dump> before
171 converting into a tree. It is used by the default implementation of
172 L</dump>.
173
174 =item C<to_object>
175
176 Converts the dumped representation back to an Rose::DB::Object
177 instance. Several columns of the newly created object are cleared by
178 C<to_object> itself: the primary key columns (if any) and the columns
179 C<itime> and C<mtime> (if the object has such columns).
180
181 This function should not be overwritten by sub-classes. Instead,
182 functions can overwrite C<_fix_object> which can be used for sanitzing
183 the newly created object before handing it back to the caller.
184
185 =item C<type>
186
187 Returns the actual clipped type (e.g. C<RequirementSpecItem>). This is
188 derived from the actual class name of C<$self>.
189
190 =item C<_fix_object $object>
191
192 This function is called by L</to_object> before the object is passed
193 back to the caller. It does not do anything in the default
194 implementation, but sub-classes are free to overwrite it if they need
195 to sanitize the object. See L<SL::Clipboard::RequirementSpecItem> for
196 an example.
197
198 Its return value is ignored.
199
200 =item C<_fix_tree $tree, $object>
201
202 This function is called by L</as_tree> after dumping and before the
203 object is stored during a copy operation. In the default
204 implementation all primary key columns and the columns C<itime> and
205 C<mtime> (if the object has such columns) are removed from the tree.
206 Sub-classes are free to overwrite it if they need to sanitize the
207 tree. See L<SL::Clipboard::RequirementSpecItem> for an example.
208
209 C<$object> is just passed in for reference and should not be modified.
210
211 Its return value is ignored.
212
213 =back
214
215 =head1 BUGS
216
217 Nothing here yet.
218
219 =head1 AUTHOR
220
221 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
222
223 =cut