Projekt

Allgemein

Profil

Herunterladen (7,71 KB) Statistiken
| Zweig: | Markierung: | Revision:
package SL::DB::Helper::AttrDuration;

use strict;

use parent qw(Exporter);
our @EXPORT = qw(attr_duration attr_duration_minutes);

use Carp;

sub attr_duration {
my ($package, @attributes) = @_;

_make($package, $_) for @attributes;
}

sub attr_duration_minutes {
my ($package, @attributes) = @_;

_make_minutes($package, $_) for @attributes;
}

sub _make {
my ($package, $attribute) = @_;

no strict 'refs';

*{ $package . '::' . $attribute . '_as_hours' } = sub {
my ($self, $value) = @_;

$self->$attribute(int($value) + ($self->$attribute - int($self->$attribute))) if @_ > 1;
return int($self->$attribute // 0);
};

*{ $package . '::' . $attribute . '_as_minutes' } = sub {
my ($self, $value) = @_;

$self->$attribute(int($self->$attribute) * 1.0 + ($value // 0) / 60.0) if @_ > 1;
return int(($self->$attribute // 0) * 60.0 + 0.5) % 60;
};

*{ $package . '::' . $attribute . '_as_duration_string' } = sub {
my ($self, $value) = @_;

$self->$attribute(defined($value) ? $::form->parse_amount(\%::myconfig, $value) * 1 : undef) if @_ > 1;
return defined($self->$attribute) ? $::form->format_amount(\%::myconfig, $self->$attribute // 0, 2) : undef;
};

*{ $package . '::' . $attribute . '_as_man_days' } = sub {
my ($self, $value) = @_;

if (@_ > 1) {
return undef if !defined $value;
$self->$attribute($value);
}
$value = $self->$attribute // 0;
return $value >= 8.0 ? $value / 8.0 : $value;
};

*{ $package . '::' . $attribute . '_as_man_days_unit' } = sub {
my ($self, $unit) = @_;

if (@_ > 1) {
return undef if !defined $unit;
croak "Unknown unit '${unit}'" if $unit !~ m/^(?:h|hour|man_day)$/;
$self->$attribute(($self->$attribute // 0) * 8.0) if $unit eq 'man_day';
}

return ($self->$attribute // 0) >= 8.0 ? 'man_day' : 'h'
};

*{ $package . '::' . $attribute . '_as_man_days_string' } = sub {
my ($self, $value) = @_;
my $method = "${attribute}_as_man_days";

if (@_ > 1) {
return undef if !defined $value;
$self->$method($::form->parse_amount(\%::myconfig, $value));
}

return $::form->format_amount(\%::myconfig, $self->$method // 0, 2);
};
}

sub _make_minutes {
my ($package, $attribute) = @_;

no strict 'refs';

*{ $package . '::' . $attribute . '_as_hours' } = sub {
my ($self, $value) = @_;

$self->$attribute($value * 60 + ($self->$attribute % 60)) if @_ > 1;
return int(($self->$attribute // 0) / 60);
};

*{ $package . '::' . $attribute . '_as_minutes' } = sub {
my ($self, $value) = @_;

$self->$attribute(int($self->$attribute) - (int($self->$attribute) % 60) + ($value // 0)) if @_ > 1;
return ($self->$attribute // 0) % 60;
};

*{ $package . '::' . $attribute . '_as_duration_string' } = sub {
my ($self, $value) = @_;

if (@_ > 1) {
if (!defined($value) || ($value eq '')) {
$self->$attribute(undef);
} else {
croak $::locale->text("Invalid duration format") if $value !~ m{^(?:(\d*):)?(\d+)$};
$self->$attribute(($1 // 0) * 60 + ($2 // 0));
}
}

my $as_hours = "${attribute}_as_hours";
my $as_minutes = "${attribute}_as_minutes";
return defined($self->$attribute) ? sprintf('%d:%02d', $self->$as_hours, $self->$as_minutes) : undef;
};

*{ $package . '::' . $attribute . '_in_hours' } = sub {
my ($self, $value) = @_;

$self->$attribute(int($value * 60 + 0.5)) if @_ > 1;
return $self->$attribute / 60.0;
};

*{ $package . '::' . $attribute . '_in_hours_as_number' } = sub {
my ($self, $value) = @_;

my $sub = "${attribute}_in_hours";

$self->$sub($::form->parse_amount(\%::myconfig, $value)) if @_ > 1;
return $::form->format_amount(\%::myconfig, $self->$sub, 2);
};
}

1;
__END__

=pod

=encoding utf8

=head1 NAME

SL::DB::Helper::AttrDuration - Attribute helper for duration stored in
numeric columns

=head1 SYNOPSIS

# In a Rose model:
use SL::DB::Helper::AttrDuration;
__PACKAGE__->attr_duration('time_estimation');
__PACKAGE__->attr_duration_minutes('hours');

# Read access:
print "Minutes: " . $obj->time_estimation_as_minutes . " hours: " . $obj->time_estimation_as_hours . "\n";

# Use formatted strings in input fields in templates:
<form method="post">
...
[% L.input_tag('time_estimation_as_duration_string', SELF.obj.time_estimation_as_duration_string) %]
</form>

=head1 OVERVIEW

This is a helper for columns that store a duration in one of two formats:

=over 2

=item 1. as a numeric or floating point number representing a number
of hours

=item 2. as an integer presenting a number of minutes

=back

In the first case the value 1.75 would stand for "1 hour, 45
minutes". In the second case the value 105 represents the same
duration.

The helper methods created depend on the mode. Calling
C<attr_duration> makes the following methods available:

=over 4

=item C<attribute_as_minutes [$new_value]>

Access only the minutes. Return values are in the range [0 - 59].

=item C<attribute_as_hours [$new_value]>

Access only the hours. Returns an integer value.

=item C<attribute_as_duration_string [$new_value]>

Access the full value as a formatted string according to the user's
locale settings.

=item C<attribute_as_man_days [$new_value]>

Access the attribute as a number of man days which are assumed to be 8
hours long. If the underlying attribute is less than 8 then the value
itself will be returned. Otherwise the value divided by 8 is returned.

If used as a setter then the underlying attribute is simply set to
C<$new_value>. Intentional use is to set the man days first and the
unit later, e.g.

$obj->attribute_as_man_days($::form->{attribute_as_man_days});
$obj->attribute_as_man_days_unit($::form->{attribute_as_man_days_unit});

Note that L<SL::DB::Object/assign_attributes> is aware of this and
handles this case correctly.

=item C<attribute_as_man_days_unit [$new_unit]>

Returns the unit that the number returned by L</attribute_as_man_days>
represents. This can be either C<h> if the underlying attribute is
less than 8 and C<man_day> otherwise.

If used as a setter then the underlying attribute is multiplied by 8
if C<$new_unit> equals C<man_day>. Otherwise the underlying attribute
is not modified. Intentional use is to set the man days first and the
unit later, e.g.

$obj->attribute_as_man_days($::form->{attribute_as_man_days});
$obj->attribute_as_man_days_unit($::form->{attribute_as_man_days_unit});

Note that L<SL::DB::Object/assign_attributes> is aware of this and
handles this case correctly.

=back

With C<attr_duration_minutes> the following methods are available:

=over 4

=item C<attribute_as_minutes [$new_value]>

Access only the minutes. Return values are in the range [0 - 59].

=item C<attribute_as_hours [$new_value]>

Access only the hours. Returns an integer value.

=item C<attribute_as_duration_string [$new_value]>

Access the full value as a formatted string in the form C<h:mm>,
e.g. C<1:30> for the value 90 minutes. Parsing such a string is
supported, too.

=item C<attribute_in_hours [$new_value]>

Access the full value but convert to and from hours when
reading/writing the value.

=item C<attribute_in_hours_as_number [$new_value]>

Access the full value but convert to and from hours when
reading/writing the value. The value is formatted to/parsed from the
user's number format.

=back

=head1 FUNCTIONS

=over 4

=item C<attr_duration @attributes>

Package method. Call with the names of attributes for which the helper
methods should be created.

=item C<attr_duration_minutes @attributes>

Package method. Call with the names of attributes for which the helper
methods should be created.

=back

=head1 BUGS

Nothing here yet.

=head1 AUTHOR

Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>

=cut
(6-6/38)