source: trunk/LATMOS-Accounts/lib/LATMOS/Accounts/Bases/Attributes.pm @ 1567

Last change on this file since 1567 was 1567, checked in by nanardon, 9 years ago

Fix returned value and test

  • Property svn:keywords set to Id
File size: 10.2 KB
Line 
1package LATMOS::Accounts::Bases::Attributes;
2
3# $Id$
4
5use strict;
6use warnings;
7use LATMOS::Accounts::Log;
8
9=head1 NAME
10
11    LATMOS::Accounts::Bases::Attributes - Object to handle attribute schema
12
13=head1 FUNCTIONS
14
15=head2 new($attributes, $base_or_object, $maybe_otype)
16
17Instanciate a new Attributes object.
18
19=cut
20
21sub new {
22    my ($class, $attributes, $base_or_object, $maybe_otype) = @_;
23   
24    my ($object, $base, $otype) =
25    $base_or_object->isa('LATMOS::Accounts::Bases::Objects')
26        ? ($base_or_object, $base_or_object->base, $base_or_object->type)
27        : (undef, $base_or_object, $maybe_otype);
28
29    if (ref $attributes) {
30        $attributes->{_base} = $base;
31        $attributes->{_object} = $object;
32        $attributes->{_name} = $attributes->{name};
33        $attributes->{_otype} = $otype;
34        return bless($attributes, $class);
35    } else {
36        my $attr_info = $base->get_attr_schema($otype, $attributes) or return;
37
38        $attr_info->{_base} = $base;
39        $attr_info->{_object} = $object;
40        $attr_info->{_name} = $attributes;
41        $attr_info->{_otype} = $otype;
42
43        return bless($attr_info, $class);
44    }
45}
46
47=head2 base
48
49Return base handle
50
51=cut
52
53sub base  { $_[0]->{_base}  }
54
55=head2 name
56
57Return attribute name
58
59=cut
60
61sub name  { $_[0]->{_name}  }
62
63=head2 otype
64
65Return object type for this attribute
66
67=cut
68
69
70sub otype { $_[0]->{_otype} }
71
72=head2 mandatory
73
74Return true if attribute is mandatory
75
76=cut
77
78sub mandatory { $_[0]->{mandatory} || 0 }
79
80=head2 object
81
82Return handle object if any
83
84=cut
85
86sub object { $_[0]->{_object} }
87
88=head2 reference
89
90A object type this attribute refer to
91
92=cut
93
94sub reference {
95    my ($self) = @_;
96    if ($self->{reference} &&
97        $self->base->is_supported_object($self->{reference})) {
98        return $self->{reference};
99    } else {
100        return;
101    }
102}
103
104=head2 iname
105
106Return internal name of attributes
107
108=cut
109
110sub iname { $_[0]->{iname} || $_[0]->name }
111
112=head2 label
113
114Return the label to display
115
116=cut
117
118sub label { $_[0]->{label} || $_[0]->{_name} }
119
120=head2 has_values_list
121
122Return true if the attribute have a fixed list of accepted values
123
124=cut
125
126sub has_values_list {
127    my ($self) = @_;
128    if ($self->base->obj_attr_allowed_values(
129        $self->otype,
130        $self->name) ||
131        $self->{can_values} ||
132        $self->reference) {
133        return 1;
134    } else {
135        return 0;
136    }
137}
138
139=head2 can_values
140
141Return possible value allowed by this attribute
142
143=cut
144
145sub can_values {
146    my ($self) = @_;
147    if (my @values = $self->base->obj_attr_allowed_values(
148            $self->otype,
149            $self->name)) {
150        return @values;
151    } elsif ($self->{can_values}) {
152        if (ref $self->{can_values} eq 'ARRAY') {
153            return @{$self->{can_values}};
154        } elsif (ref $self->{can_values} eq 'CODE') {
155            $self->{can_values}->($self, $self->object);
156        } else {
157            return;
158        }
159    } elsif (my $ref = $self->reference) {
160        return $self->base->list_objects($ref);
161    } else { return }
162}
163
164=head2 display ($value)
165
166Return the well formated value according attribute
167
168=cut
169
170sub display {
171    my ($self, $value) = @_;
172    if ($self->{display}) {
173        return $self->{display}->($self, $value);
174    } else {
175        return $value;
176    }
177}
178
179=head2 input ($value)
180
181Return well formated single value for insert into base
182
183=cut
184
185sub input {
186    my ($self, $value) = @_;
187    if ($self->{input}) {
188        if (!defined($value)) { return }
189        return $self->{input}->($value);
190    } else {
191        return $value;
192    }
193}
194
195=head2 checkinputformat ($value)
196
197Check input value format, return false on error
198
199=cut
200
201sub checkinputformat {
202    my ($self, $value) = @_;
203
204    if ($self->{checkinputformat}) {
205        if (!$self->{checkinputformat}->($value)) {
206           return;
207        }
208    }
209
210    return 1;
211}
212
213=head2 checkinput ($value)
214
215Check input value, return false on error
216
217=cut
218
219sub checkinput {
220    my ($self, $values) = @_;
221
222    foreach my $value (ref $values ? @{ $values } : $values) {
223        if (!$self->checkinputformat($value)) {
224            $self->base->log(LA_ERR, "Wrong format for  %s/%s: %s",
225               $self->name,
226               $self->{_otype},
227               $value
228            );
229            return;
230        }
231    }
232
233    if ($self->mandatory &&
234        (!(defined($values)) || $values eq '')) {
235        $self->base->log(LA_ERR,
236            "%s attribute cannot be empty for object %s",
237            $self->name,
238            $self->{_otype},
239        );
240        return;
241    }
242
243    if ($self->has_values_list && $values) {
244        my @possible = $self->can_values;
245        foreach my $value (ref $values ? @{ $values } : $values) {
246            if (! grep { $value eq $_ } @possible) {
247                $self->base->log(LA_ERR,
248                    "%s attribute cannot have `%s' as value for object %s/%s",
249                    $self->name,
250                    $value,
251                    $self->object->type,
252                    $self->object->id,
253                ) if ($self->object);
254                $self->base->log(LA_DEBUG, "Possible value for %s: %s",
255                    $self->name,
256                    join(', ', @possible)
257                );
258                return;
259            }
260        }
261    }
262
263    if (ref $values eq 'ARRAY' && ! $self->multiple) {
264        $self->base->log(LA_WARN, 'Attribute %s is not multi valuesd', $self->name);
265        # TODO: really return an error
266        # return;
267    }
268
269    if ($self->{checkinput}) {
270        foreach my $val (ref $values ? @{ $values } : $values) {
271            if (!$self->{checkinput}->($val)) {
272                return;
273            }
274        }
275    }
276
277    return 1;
278}
279
280=head2 readable
281
282Return true if attribute can be read
283
284=cut
285
286sub readable {
287    my ($self) = @_;
288    if (ref $self->{readable} eq 'CODE') {
289        return $self->{readable}->($self->object) || 0;
290    } else {
291        return defined($_[0]->{readable}) ? $_[0]->{readable} : 1;
292    }
293}
294
295=head2 ro
296
297Return true if the attribute cannot be write by design
298
299=cut
300
301sub ro {
302    my ($self) = @_;
303    if (ref $self->{ro} eq 'CODE') {
304        return $self->{ro}->($self->object) || 0;
305    } else {
306        return $_[0]->{ro} || 0 
307    }
308}
309
310=head2 readonly
311
312Return true if attribute cannot be read according acls or attributes state
313
314=cut
315
316sub readonly { 
317    my ($self) = @_;
318    return 1 if ($self->ro);
319   
320    return ! $self->check_acl('w');
321}
322
323=head2 check_acl ($mode)
324
325Return true is access to C<$mode> is granted
326
327=cut
328
329sub check_acl {
330    my ($self, $mode) = @_;
331
332    return 1 if ($self->{_noacl});
333
334    return $self->base->check_acl($self->object
335        ? ($self->object, $self->name, $mode)
336        : ($self->otype, '@CREATE', $mode));
337}
338
339=head2 real_form_type
340
341Return the way the fields must be show in GUI.
342For each type option maybe given by form_option
343
344=head3 LABEL
345
346=over 4
347
348=item length
349
350The length to use to show the attribute
351
352=back
353
354=head3 TEXT
355
356=head3 TEXTAREA
357
358=head3 DATE
359
360=head3 LIST
361
362=head3 CHECKBOX
363
364=over 4
365
366=item rawvalue
367
368The real value of the attribute must be show
369
370=back
371
372=cut
373
374sub real_form_type { $_[0]->{formtype} || 'TEXT' }
375
376=head2 form_type
377
378Return the way the attribute must be displayed
379
380=cut
381
382sub form_type {
383    $_[0]->readonly ? 'LABEL' :
384    $_[0]->{formtype} ? $_[0]->{formtype} :
385    $_[0]->has_values_list ? 'LIST' :
386    $_[0]->real_form_type
387}
388
389=head2 form_option ($option)
390
391Return the form option C<$option>
392
393=cut
394
395sub form_option {
396    my ($self, $option) = @_;
397    return $self->{formopts}{$option}
398}
399
400=head2 uniq
401
402Return true is attribute value must be uniq
403
404=cut
405
406sub uniq { $_[0]->{uniq} || 0 }
407
408=head2 multiple
409
410Return true is attribute value can be set several times
411
412=cut
413
414sub multiple { $_[0]->{multiple} || 0 }
415
416=head2 hidden
417
418Return true if attributes must not appear in list by can be query.
419
420=cut
421
422sub hidden { $_[0]->{hide} || 0 }
423
424=head2 delayed
425
426Return true if attribute must be set after object creation during
427synchronisation
428
429=cut
430
431sub delayed { $_[0]->{delayed} || 0 }
432
433=head2 get
434
435Return the value for this attribute
436
437=cut
438
439sub get {
440    my ($self) = @_;
441
442    if (defined($self->object)) {
443        my $res = (ref($self->{get}) eq 'CODE')
444            ? $self->{get}->($self)
445            : $self->object->get_field($self->iname);
446
447        # always return undef if empty
448        # and an array if attribute is multivalued
449        if (!$res) {
450            return undef;
451        } elsif (ref $res) {
452            return @{$res} ? $res : undef;
453        } elsif ($self->multiple) {
454            return (ref $res ? $res : [$res])
455        } else {
456            return $res;
457        }
458    } else {
459        return;
460    }
461}
462
463=head2 defaultValue
464
465Return the default static value for this attribute.
466
467=cut
468
469sub defaultValue {
470    my ($self) = @_;
471
472    return $self->base->defaultAttributeValue($self->otype, $self->name)
473}
474
475=head2 getValues
476
477Return value for this attribute, results are always return as an array
478
479=cut
480
481sub getValues {
482    my ($self) = @_;
483
484    my $res = $self->get();
485
486    return ref $res ? grep { $_ } @{ $res } : $res;
487}
488
489
490=head2 set ($values)
491
492Set attribute value to attached object
493
494=cut
495
496sub set {
497    my ($self, $values) = @_;
498
499    my $inputv = ref $values
500        ? [ map { $self->input($_) } @$values ]
501        : $values ? $self->input($values) : undef;
502
503    my $res = ref $self->{set} eq 'CODE'
504        ? $self->{set}->($self, $inputv)
505        : $self->object->set_fields($self->iname, $inputv);
506
507    # If the attribute has a post code, call it
508    if ($res && $self->{post}) {
509        $self->{post}->($self, $inputv);
510    }
511
512    $res
513}
514
515=head2 default_value
516
517Return default value for this attribute
518
519=cut
520
521sub default_value {
522    my ($self) = @_;
523    $self->defaultValue;
524}
525
526=head2 monitored
527
528Return true if the attribute is monitored
529
530=cut
531
532sub monitored {
533    my ($self) = @_;
534
535    if ($self->iname ne $self->name) {
536        my $attr = $self->base->attribute($self->otype, $self->iname) or return;
537        return $attr->monitored;
538    } else {
539        return $self->{monitored} || 0;
540    }
541}
542
5431;
544
545__END__
546
547=head1 SEE ALSO
548
549L<LATMOS::Accounts::Bases>
550
551=head1 AUTHOR
552
553Olivier Thauvin, E<lt>olivier.thauvin@latmos.ipsl.frE<gt>
554
555=head1 COPYRIGHT AND LICENSE
556
557Copyright (C) 2012 CNRS SA/CETP/LATMOS
558
559This library is free software; you can redistribute it and/or modify
560it under the same terms as Perl itself, either Perl version 5.10.0 or,
561at your option, any later version of Perl 5 you may have available.
562
563=cut
Note: See TracBrowser for help on using the repository browser.