use Carp;
use List::Util qw(max);
+use Scalar::Util qw(blessed);
use SL::Common;
use SL::MoreCommon;
my @columns = $params{report}->get_visible_columns('HTML');
for my $obj (@{ $params{objects} || [] }) {
- my %data = map {
- my $def = $column_defs->{$_};
- my $tmp;
- $tmp->{raw_data} = $def->{raw_data} ? $def->{raw_data}->($obj) : '';
- $tmp->{data} = $def->{sub} ? $def->{sub}->($obj)
- : $obj->can($_) ? $obj->$_
- : $obj->{$_};
- $tmp->{link} = $def->{obj_link} ? $def->{obj_link}->($obj) : '';
- $_ => $tmp;
- } @columns;
+ my %data;
+
+ if (blessed($obj) && $obj->isa('SL::Controller::Helper::ReportGenerator::ControlRow::Base')) {
+ $obj->set_data($params{report});
+ next;
+
+ } else {
+ %data = map {
+ my $def = $column_defs->{$_};
+ my $tmp;
+ $tmp->{raw_data} = $def->{raw_data} ? $def->{raw_data}->($obj) : '';
+ $tmp->{data} = $def->{sub} ? $def->{sub}->($obj)
+ : $obj->can($_) ? $obj->$_
+ : $obj->{$_};
+ $tmp->{link} = $def->{obj_link} ? $def->{obj_link}->($obj) : '';
+ $_ => $tmp;
+ } @columns;
+ }
$params{data_callback}->(\%data) if $params{data_callback};
Mandatory. An array reference of RDBO models to output.
+An element of the array can also be an instance of a control row, i.e.
+an instance of a class derived from
+C<SL::Controller::Helper::ReportGenerator::ControlRow::Base>.
+See also:
+
+L<SL::Controller::Helper::ReportGenerator::ControlRow>
+L<SL::Controller::Helper::ReportGenerator::ControlRow::*>
+
=item C<data_callback>
Optional. A callback handler (code reference) that gets called for
--- /dev/null
+package SL::Controller::Helper::ReportGenerator::ControlRow;
+
+use strict;
+use Carp;
+
+use SL::Controller::Helper::ReportGenerator::ControlRow::ALL;
+
+use Exporter 'import';
+our @EXPORT = qw(
+ make_control_row
+);
+
+
+sub make_control_row {
+ my ($type, %args) = @_;
+
+ my $class = $SL::Controller::Helper::ReportGenerator::ControlRow::ALL::type_to_class{$type} // croak "unknown type $type";
+ my $obj = $class->new(params => \%args);
+ my @errors = $obj->validate_params;
+ croak join("\n", @errors) if @errors;
+
+ return $obj;
+}
+
+
+1;
+
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+SL::Controller::Helper::ReportGenerator::ControlRow - an interface for
+report generator control rows
+
+=head1 DESCRIPTION
+
+ControlRow is an interface that allows generic control rows to be added
+to objects for the C<SL::Controller::Helper::ReportGenerator>.
+
+Each control row implementation can access the report and add data for a row.
+
+=head1 SYNOPSIS
+
+ package SL::Controller::TimeRecording;
+
+ use SL::Controller::Helper::ReportGenerator;
+ use SL::Controller::Helper::ReportGenerator::ControlRow qw(make_control_row);
+
+ sub action_list {
+ my ($self) = @_;
+
+ # Set up the report generator instance. In this example this is
+ # hidden in "prepare_report".
+ my $report = $self->prepare_report;
+
+ # Get objects from database.
+ my $objects = SL::DB::Manager::TimeRecording->get_all(...);
+
+ # Add a separator
+ push @$objects, make_control_row("separator");
+
+ # And a simple total
+ my $total = sum0 map { _round_total($_->duration_in_hours) } @$objects;
+ push @$objects, make_control_row("simple_data", data => {duration => $total});
+
+ # Let report generator create the output.
+ $self->report_generator_list_objects(
+ report => $report,
+ objects => $objects,
+ );
+ }
+
+
+=head1 WRITING OWN CONTROL ROW CLASSES
+
+See C<SL::Controller::Helper::ReportGenerator::ControlRow::Base>.
+
+=head1 FUNCTIONS
+
+=over 4
+
+=item C<make_control_row TYPE %PARAMS>
+
+Returns an instance of the control row class for the given type. This
+object can be used as an element of objects to the report generator helper
+(see C<SL::Controller::Helper::ReportGenerator>).
+
+Available types are 'separator', 'data, 'simple_data' for now.
+
+C<%PARAMS> depends on the type. See also:
+
+L<SL::Controller::Helper::ReportGenerator::ControlRow::ALL>
+L<SL::Controller::Helper::ReportGenerator::ControlRow::*>
+
+=back
+
+=head1 AUTHOR
+
+Bernd Bleßmann E<lt>bernd@kivitendo-premium.deE<gt>
+
+=cut
--- /dev/null
+package SL::Controller::Helper::ReportGenerator::ControlRow::ALL;
+
+use strict;
+
+use SL::Controller::Helper::ReportGenerator::ControlRow::Data;
+use SL::Controller::Helper::ReportGenerator::ControlRow::Separator;
+use SL::Controller::Helper::ReportGenerator::ControlRow::SimpleData;
+
+our %type_to_class = (
+ data => 'SL::Controller::Helper::ReportGenerator::ControlRow::Data',
+ separator => 'SL::Controller::Helper::ReportGenerator::ControlRow::Separator',
+ simple_data => 'SL::Controller::Helper::ReportGenerator::ControlRow::SimpleData',
+);
+
+1;
--- /dev/null
+package SL::Controller::Helper::ReportGenerator::ControlRow::Base;
+
+use strict;
+
+use parent qw(SL::DB::Object);
+
+use Rose::Object::MakeMethods::Generic (
+ scalar => [ qw(params) ],
+);
+
+
+sub validate_params { die 'name needs to be implemented' }
+sub set_data { die 'name needs to be implemented' }
+
+
+1;
+
+
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+SL::Controller::Helper::ReportGenerator::ControlRow::Base - a base class
+for report generator control row classes
+
+=head1 DESCRIPTION
+
+ControlRow is an interface that allows generic control rows to be added
+to objects for the C<SL::Controller::Helper::ReportGenerator>. This is a
+base class from which all control row classes are derived.
+
+=head1 SYNOPSIS
+
+Adding your own new control row of the type "only_dashes":
+
+ package SL::Controller::Helper::ReportGenerator::ControlRow::OnlyDashes;
+
+ use parent qw(SL::Controller::Helper::ReportGenerator::ControlRow::Base);
+
+ sub validate_params { return; } # no params
+
+ sub set_data {
+ my ($self, $report) = @_;
+
+ my %data = map { $_ => {data => '---'} } keys %{ $report->{columns} };
+
+ $report->add_data(\%data);
+ }
+
+After that, you have to register your new class in
+C<SL::Controller::Helper::ReportGenerator::ControlRow::ALL>:
+
+ use SL::Controller::Helper::ReportGenerator::ControlRow::OnlyDashes;
+
+ our %type_to_class = (
+ ...,
+ only_dashes => 'SL::Controller::Helper::ReportGenerator::ControlRow::OnlyDashes',
+ );
+
+
+=head1 WRITING OWN CONTROL ROW CLASSES
+
+You can use C<SL::Controller::Helper::ReportGenerator::ControlRow::Base>
+as parent of your module. You have to provide two methods:
+
+=over 4
+
+=item C<validate_params>
+
+This method is used to validate any params used for your module.
+You can access the params through the method C<params> which contains all
+remaining params after the type of the call to make_control_row (see
+C<SL::Controller::Helper::ReportGenerator::ControlRow>).
+
+The method should return an array of error messages if there are any
+errors. Otherwise it should return C<undef>.
+
+=item C<set_data REPORT>
+
+This method sould set the data for the report generator, which is handeled
+over as argument.
+
+=back
+
+=head1 REGISTERING OWN CONTROL ROW CLASSES
+
+See C<SL::Controller::Helper::ReportGenerator::ControlRow::ALL>. Here your
+class should be included with C<use> and entered in the map C<%type_to_class>
+with an appropiate name for it's type.
+
+
+=head1 AUTHOR
+
+Bernd Bleßmann E<lt>bernd@kivitendo-premium.deE<gt>
+
+=cut
--- /dev/null
+package SL::Controller::Helper::ReportGenerator::ControlRow::Data;
+
+use strict;
+
+use parent qw(SL::Controller::Helper::ReportGenerator::ControlRow::Base);
+
+
+sub validate_params {
+ my ($self) = @_;
+
+ my @errors;
+ push @errors, 'type "data" needs a parameter "row" as hash ref' if !$self->params->{row} || ('HASH' ne ref $self->params->{row});
+
+ return @errors;;
+}
+
+sub set_data {
+ my ($self, $report) = @_;
+
+ my %data;
+ %data = map {
+ my $def = $self->params->{row}->{$_};
+ my $tmp;
+
+ foreach my $attr (qw(raw_data data link class align)) {
+ $tmp->{$attr} = $def->{$attr} if defined $def->{$attr};
+ }
+ $_ => $tmp;
+ } keys %{ $self->params->{row} };
+
+ $report->add_data(\%data);
+}
+
+
+1;
+
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+SL::Controller::Helper::ReportGenerator::ControlRow::Data - an
+implementaion of a control row class to display data
+
+=head1 DESCRIPTION
+
+This class implements a control row for the report generator helper to display
+data. You can configure the way the data is displayed.
+
+=head1 SYNOPSIS
+
+ use SL::Controller::Helper::ReportGenerator;
+ use SL::Controller::Helper::ReportGenerator::ControlRow qw(make_control_row);
+
+ sub action_list {
+ my ($self) = @_;
+
+ # Set up the report generator instance. In this example this is
+ # hidden in "prepare_report".
+ my $report = $self->prepare_report;
+
+ # Get objects from database.
+ my $objects = SL::DB::Manager::TimeRecording->get_all(...);
+
+ # Add a simple data
+ my $total = $self->get_total($objects);
+ push @$objects, make_control_row(
+ "data",
+ row => { duration => { data => $total,
+ class => 'listtotal',
+ link => '#info_for_total' } }
+ );
+
+ # Let report generator create the output.
+ $self->report_generator_list_objects(
+ report => $report,
+ objects => $objects,
+ );
+ }
+
+=head1 PARAMETERS
+
+This control row gets the paramter C<row>, which must a hash ref.
+The keys are the column names for the fields you want to show your
+data. The values are hash refs itself and can contain the keys
+C<raw_data>, C<data>, C<link>, C<class> and C<align> which are passed
+in the data added to the report.
+
+=head1 AUTHOR
+
+Bernd Bleßmann E<lt>bernd@kivitendo-premium.deE<gt>
+
+=cut
--- /dev/null
+package SL::Controller::Helper::ReportGenerator::ControlRow::Separator;
+
+use strict;
+
+use parent qw(SL::Controller::Helper::ReportGenerator::ControlRow::Base);
+
+
+sub validate_params {
+ return;
+}
+
+sub set_data {
+ my ($self, $report) = @_;
+
+ $report->add_separator();
+}
+
+
+1;
+
+
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+SL::Controller::Helper::ReportGenerator::ControlRow::Separator - an
+implementaion of a control row class to display a separator
+
+=head1 DESCRIPTION
+
+This class implements a control row for the report generator helper to display
+a separator.
+
+=head1 SYNOPSIS
+
+ use SL::Controller::Helper::ReportGenerator;
+ use SL::Controller::Helper::ReportGenerator::ControlRow qw(make_control_row);
+
+ sub action_list {
+ my ($self) = @_;
+
+ # Set up the report generator instance. In this example this is
+ # hidden in "prepare_report".
+ my $report = $self->prepare_report;
+
+ # Get objects from database.
+ my $objects = SL::DB::Manager::TimeRecording->get_all(...);
+
+ # Add a separator
+ push @$objects, make_control_row("separator");
+
+ # Let report generator create the output.
+ $self->report_generator_list_objects(
+ report => $report,
+ objects => $objects,
+ );
+ }
+
+=head1 PARAMETERS
+
+This control row does not use any parameters.
+
+=head1 AUTHOR
+
+Bernd Bleßmann E<lt>bernd@kivitendo-premium.deE<gt>
+
+=cut
--- /dev/null
+package SL::Controller::Helper::ReportGenerator::ControlRow::SimpleData;
+
+use strict;
+
+use parent qw(SL::Controller::Helper::ReportGenerator::ControlRow::Base);
+
+
+sub validate_params {
+ my ($self) = @_;
+
+ my @errors;
+ push @errors, 'type "simple_data" needs a parameter "data" as hash ref' if !$self->params->{data} || ('HASH' ne ref $self->params->{data});
+
+ return @errors;
+}
+
+sub set_data {
+ my ($self, $report) = @_;
+
+ my %data = map {
+ my $tmp;
+ $tmp->{data} = $self->params->{data}->{$_};
+ $_ => $tmp;
+ } keys %{ $self->params->{data} };
+
+ $report->add_data(\%data);
+}
+
+
+1;
+
+
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+SL::Controller::Helper::ReportGenerator::ControlRow::SimpleData - an
+implementaion of a control row class to display simple data
+
+=head1 DESCRIPTION
+
+This class implements a control row for the report generator helper to display
+simple data. C<Simple> because you only have to provide the column and your data
+as a string.
+
+=head1 SYNOPSIS
+
+ use SL::Controller::Helper::ReportGenerator;
+ use SL::Controller::Helper::ReportGenerator::ControlRow qw(make_control_row);
+
+ sub action_list {
+ my ($self) = @_;
+
+ # Set up the report generator instance. In this example this is
+ # hidden in "prepare_report".
+ my $report = $self->prepare_report;
+
+ # Get objects from database.
+ my $objects = SL::DB::Manager::TimeRecording->get_all(...);
+
+ # Add a simple data
+ push @$objects, make_control_row(
+ "simple_data",
+ data => { duration => 'Total sum of duration is not implemeted yet' }
+ );
+
+ # Let report generator create the output.
+ $self->report_generator_list_objects(
+ report => $report,
+ objects => $objects,
+ );
+ }
+
+=head1 PARAMETERS
+
+This control row gets the paramter C<data>, which must a hash ref.
+The keys are the column names for the fields you want to show your
+data. The values are the data.
+
+=head1 AUTHOR
+
+Bernd Bleßmann E<lt>bernd@kivitendo-premium.deE<gt>
+
+=cut