1 package SL::DB::Object;
5 use English qw(-no_match_vars);
7 use List::MoreUtils qw(any);
10 use SL::DB::Helper::Attr;
11 use SL::DB::Helper::Metadata;
12 use SL::DB::Helper::Manager;
13 use SL::DB::Object::Hooks;
15 use base qw(Rose::DB::Object);
19 my $self = $class->SUPER::new();
21 $self->_assign_attributes(@_) if $self;
27 my $class_or_self = shift;
28 my $class = ref($class_or_self) || $class_or_self;
29 my $type = $class =~ m/::Auth/ ? 'LXOFFICE_AUTH' : 'LXOFFICE';
31 return SL::DB::create(undef, $type);
35 return 'SL::DB::Helper::Metadata';
38 sub _get_manager_class {
39 my $class_or_self = shift;
40 my $class = ref($class_or_self) || $class_or_self;
42 return $class->meta->convention_manager->auto_manager_class_name($class);
45 my %text_column_types = (text => 1, char => 1, varchar => 1);
47 sub assign_attributes {
51 my $pk = ref($self)->meta->primary_key;
52 delete @attributes{$pk->column_names} if $pk;
54 return $self->_assign_attributes(%attributes);
57 sub _assign_attributes {
61 my %types = map { $_->name => $_->type } ref($self)->meta->columns;
63 while (my ($attribute, $value) = each %attributes) {
64 my $type = lc($types{$attribute} || 'text');
65 $value = $type eq 'boolean' ? ($value ? 't' : 'f')
66 : $text_column_types{$type} ? $value
67 : defined($value) && ($value eq '') ? undef
69 $self->$attribute($value);
75 sub update_attributes {
78 $self->assign_attributes(@_)->save;
86 return $self->$sub(@_);
94 $check = $check->($self) if ref($check) eq 'CODE';
96 return $check ? $self->$sub(@_) : $self;
99 sub get_first_conflicting {
100 my ($self, @attributes) = @_;
102 my $primary_key = ($self->meta->primary_key)[0];
103 my @where = map { ($_ => $self->$_) } @attributes;
105 push @where, ("!$primary_key" => $self->$primary_key) if $self->$primary_key;
107 return $self->_get_manager_class->get_first(where => [ and => \@where ]);
110 # These three functions cannot sit in SL::DB::Object::Hooks because
111 # mixins don't deal well with super classes (SUPER is the current
112 # package's super class, not $self's).
114 my ($self, @args) = @_;
116 SL::DB::Object::Hooks::run_hooks($self, 'before_load');
117 my $result = $self->SUPER::load(@args);
118 SL::DB::Object::Hooks::run_hooks($self, 'after_load', $result);
124 my ($self, @args) = @_;
126 my ($result, $exception);
128 SL::DB::Object::Hooks::run_hooks($self, 'before_save');
129 $exception = $EVAL_ERROR unless eval {
130 $result = $self->SUPER::save(@args);
133 SL::DB::Object::Hooks::run_hooks($self, 'after_save', $result);
138 $self->db->in_transaction ? $worker->() : $self->db->do_transaction($worker);
140 die $exception if $exception;
146 my ($self, @args) = @_;
148 my ($result, $exception);
150 SL::DB::Object::Hooks::run_hooks($self, 'before_delete');
151 $exception = $EVAL_ERROR unless eval {
152 $result = $self->SUPER::delete(@args);
155 SL::DB::Object::Hooks::run_hooks($self, 'after_delete', $result);
160 $self->db->in_transaction ? $worker->() : $self->db->do_transaction($worker);
162 die $exception if $exception;
175 SL::DB::Object: Base class for all of our model classes
179 This is the base class from which all other model classes are
180 derived. It contains functionality and settings required for all model
183 Several functions (e.g. C<make_manager_class>, C<init_db>) in this
184 class are used for setting up the classes / base classes used for all
185 model instances. They overwrite the functions from
192 =item assign_attributes %attributes
194 =item _assign_attributes %attributes
196 Assigns all elements from C<%attributes> to the columns by calling
197 their setter functions. The difference between the two functions is
198 that C<assign_attributes> protects primary key columns while
199 C<_assign_attributes> doesn't.
201 Both functions handle values that are empty strings by replacing them
202 with C<undef> for non-text columns. This allows the calling functions
203 to use data from HTML forms as the input for C<assign_attributes>
204 without having to remove empty strings themselves (think of
205 e.g. select boxes with an empty option which should be turned into
206 C<NULL> in the database).
208 =item update_attributes %attributes
210 Assigns the attributes from C<%attributes> by calling the
211 C<assign_attributes> function and saves the object afterwards. Returns
214 =item _get_manager_class
216 Returns the manager package for the object or class that it is called
217 on. Can be used from methods in this package for getting the actual
220 =item C<call_sub $name, @args>
222 Calls the sub C<$name> on C<$self> with the arguments C<@args> and
223 returns its result. This is meant for situations in which the sub's
224 name is a composite, e.g.
226 my $chart_id = $buchungsgruppe->call_sub(($is_sales ? "income" : "expense") . "_accno_id_${taxzone_id}");
228 =item C<call_sub_if $name, $check, @args>
230 Calls the sub C<$name> on C<$self> with the arguments C<@args> if
231 C<$check> is trueish. If C<$check> is a code reference then it will be
232 called with C<$self> as the only argument and its result determines
233 whether or not C<$name> is called.
235 Returns the sub's result if the check is positive and C<$self>
238 =item C<get_first_conflicting @attributes>
240 Returns the first object for which all properties listed in
241 C<@attributes> equal those in C<$self> but which is not C<$self>. Can
242 be used to check whether or not an object's columns are unique before
243 saving or during validation.
249 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>