package Lire::Report::Entry; use strict; use Carp; use Lire::Utils qw/ xml_encode check_object_param /; use Lire::Report::Group; =pod =head1 NAME Lire::Report::Entry - Interface to subreport's data. =head1 SYNOPSIS foreach my $name ( $entry->names() ) { print "Name: ", $name->{'content'}, "\n"; } foreach my $value ( $entry->values() ) { if ( ref $value eq 'Lire::Report::Group' ) { # Value is a group foreach my $e ( $value->entries() ) { print_entry( $e ); } } else { print "Value: ", $value->{'content'}, "\n"; } } =head1 DESCRIPTION The Lire::Report::Entry objects are used to hold the subreport's data. =head1 CONSTRUCTOR One creates a new Entry object by using the create_entry method on a Lire::Report::Subreport or Lire::Report::Group object. Use the add_name(), create_group() and add_value() methods to fill the entry. =cut sub new { my ( $class, $group ) = @_; check_object_param( $group, 'group', 'Lire::Report::Group' ); return bless( {'data' => [], 'group' => $group}, $class ); } =pod =head1 OBJECT METHODS =head2 row_idx() Returns the row index in the table body where this entry's data should be displayed. If undef, this entry shouldn't be displayed. =cut sub row_idx { $_[0]{'row_idx'} = $_[1] if @_ == 2; return $_[0]{'row_idx'}; } =pod =head2 subreport() Returns the Lire::Report::Subreport object in which this entry is contained. =cut sub subreport { my $self = $_[0]; my $parent = $self->group(); while ( $parent && $parent->parent_entry() ) { $parent = $parent->parent_entry()->group(); } return $parent; } =pod =head2 group() Returns the Lire::Report::Group object which contains this entry. =cut sub group { return $_[0]{'group'}; } =pod =head2 group_info() Returns the Lire::Report::GroupInfo which contains the information related to the group in which this entry is. =cut sub group_info { return $_[0]{'group'}->group_info(); } =pod =head2 data() Returns as an array the data contained in this entry. This is a list of hashes or Lire::Report::Group object. =cut sub data { return @{$_[0]->{'data'}}; } =pod =head2 data_by_name( $name ) Returns the data item contained in this Entry that was generated by the operator named $name. Returns undef if no such data item can be found. =cut sub data_by_name { my ( $self, $name ) = @_; foreach my $d ( @{$self->{'data'}} ) { if ( UNIVERSAL::isa( $d, 'Lire::Report::Group' ) ) { return $d if $d->group_info()->name() eq $name; } else { return $d if $d->{'col_info'}->name() eq $name; } } return undef; } =pod =head2 names() Returns the names of the entry. This is an array of hashes. The name's hash contains the following keys: =over 4 =item type Always set to 'name'. =item content That's the actual content of the name element. This contains the name in a format suitable for display. =item value This contains the unformatted value of the name. For example, when the name is a time string, this attribute will contains the time in seconds since epoch. =item missing_cases This value contains the number of DLF records which had a undefined value in one of the required fields to compute this statistic. =item range For some names, the actual content express a range (time, size, etc.). This attribute contains the length of the range. =item col_info The Lire::Report::ColumnInfo object describing this name. =back =cut sub names { return grep { $_->{'type'} eq 'name' } @{$_[0]->{'data'}}; } =pod =head2 add_name( $content, [$value], [$range] ) Adds a new name to this entry. Consult the documentation of the names() method for a description of the meaning of the various parameters which have the same meaning as the keys with the same name. The names, values and groups should be added in the order specified by this entry's GroupInfo. You'll get an exception otherwise. =cut sub add_name { my ( $self, $content, $value, $range ) = @_; $content = '' unless defined $content; $value = $content unless defined $value; my $idx = $#{$self->{'data'}} + 1; my $info = $self->group_info->info_by_index( $idx ); check_object_param( $info, "Data_$idx", 'Lire::Report::ColumnInfo' ); my %n = ('type' => 'name', 'content' => $content, 'value' => $value, 'col_info' => $info); $n{'range'} = $range if defined $range; push @{$self->{'data'}}, \%n; return; } =pod =head2 values() Returns the values of the entry. This is an array of hashes or objects. If the value is an hash, it has the following keys: =over 4 =item type Always set to 'value'. =item content That's the actual content of the value element. This contains the value in a format suitable for display. =item value This contains the unformatted value. For example, when bytes are displayed using "1M" or "1.1G", this will contain the value in single bytes. =item missing_cases The number of DLF records which had an undefined value in one of fields required by this operator. =item total This is used by values that represent an average. It contains the total which makes up the average. =item n This is used by values that represent an average. It contains the total which was used in the division to compute the average. =item col_info The Lire::Report::ColumnInfo object describing this value. =back =cut sub values { return grep { $_->{'type'} eq 'value' } @{$_[0]->{'data'}}; } =pod =head2 groups() Returns in an array the Lire::Report::Group contained in this Entry. =cut sub groups { return grep { UNIVERSAL::isa( $_, 'Lire::Report::Group' ) } @{$_[0]->{'data'}}; } =pod =head2 create_group() Creates a new group for this entry. This will also append it to this entry data. If you create the group out of order compared to the names and values that should go in that entry, you'll get an exception. =cut sub create_group { my $self = $_[0]; my $idx = $#{$self->{'data'}} + 1; my $info = $self->group_info->info_by_index( $idx ); check_object_param( $info, "Data_$idx", 'Lire::Report::GroupInfo' ); my $group = new Lire::Report::Group( $self, $info ); push @{$self->{'data'}}, $group; return $group; } =pod =head2 add_value( %value ) Adds a new value to this entry. The value hash should at least contains the 'content' key. It can also includes values for the 'n', 'total' and 'missing_cases' keys. Consult the documentation of the values() method for a description of the meaning of the various parameters: these have the same meaning as the keys with the same names. The names, values and groups should be added in the order specified by this entry's GroupInfo. You'll get an exception otherwise. =cut sub add_value { my $self = $_[0]; my $value = ref( $_[1] ) ? $_[1] : { @_[1..$#_] }; $value->{'content'} = "" unless defined $value->{'content'}; $value->{'value'} = $value->{'content'} unless defined $value->{'value'}; my $idx = $#{$self->{'data'}} + 1; my $info = $self->group_info()->info_by_index( $idx ); check_object_param( $info, "Data_$idx", 'Lire::Report::ColumnInfo' ); $value->{'type'} = 'value'; $value->{'col_info'} = $info; $value->{'n'} = undef unless exists $value->{'n'}; $value->{'total'} = undef unless exists $value->{'total'}; $value->{'missing_cases'} = 0 unless defined $value->{'missing_cases'}; push @{$self->{'data'}}, $value; return; } # # helper method for Lire::Report::Subreport::last_row_idx() # sub _last_row_idx { my $self = $_[0]; return undef unless defined $self->{'row_idx'}; my $last = $self->{'row_idx'}; foreach my $group ( $self->groups() ) { my $group_last = $group->_last_row_idx(); $last = $group_last if defined $group_last && $group_last > $last; } return $last; } # # helper method for Lire::Report::Subreport::getrow_by_idx() # sub _getrow_by_idx { my ( $self, $idx, $row ) = @_; if ( $self->{'row_idx'} == $idx ) { foreach my $item ( @{$self->{'data'}} ) { my @cells = ( UNIVERSAL::isa( $item, 'Lire::Report::Group' ) ? $item->summary_values() : $item ); foreach my $cell ( @cells ) { $row->[$cell->{'col_info'}->col_start()] = $cell; } } } else { foreach my $group ( $self->groups() ) { $group->_getrow_by_idx( $idx, $row ); } } } #------------------------------------------------------------------------ # Method write_report( $fh, $indent ) # sub write_report { my ( $self, $fh, $indent ) = @_; $fh ||= *STDOUT; my $pfx = ' ' x $indent; print $fh $pfx, "row_idx(); print $fh ">\n"; foreach my $d ( @{$self->{'data'}} ) { if ( $d->{'type'} eq 'name' ) { write_name( $fh, $pfx, $d ); } elsif ( $d->{'type'} eq 'value' ) { write_value( $fh, $pfx, $d ); } else { # Group $d->write_report( $fh, $indent + 1 ); } } print $fh "$pfx\n"; return; } #------------------------------------------------------------------------ # Function write_name( $fh, $pfx, $d ) # # Writes $d into a lire:name element. sub write_name { my ( $fh, $pfx, $d ) = @_; print $fh $pfx, ' {'value'} ne $d->{'content'}; print $fh qq! range="$d->{'range'}"! if defined $d->{'range'}; print $fh ">", xml_encode( $d->{'content'} ), "\n"; return; } #------------------------------------------------------------------------ # Function write_value($fh, $pfx, $d) # # Writes $d into a lire:value element. sub write_value { my ( $fh, $pfx, $d ) = @_; print $fh $pfx, ' {'total'}; print $fh qq! n="$d->{'n'}"! if defined $d->{'n'}; print $fh qq! value="$d->{'value'}"! if $d->{'value'} ne $d->{'content'}; print $fh ">$d->{'content'}\n"; return; } #------------------------------------------------------------------------ # Method delete() # # Remove circular references sub delete { my $self = $_[0]; foreach my $g ( grep { $_->{'type'} eq 'group' } $self->values() ) { $g->delete(); } %$self = (); return; } # keep perl happy 1; =pod =head1 SEE ALSO Lire::ReportParser::ReportBuilder(3pm) Lire::Report(3pm) Lire::Report::Subreport(3pm) Lire::Report::Section(3pm) Lire::Report::Group(3pm) =head1 VERSION $Id: Entry.pm,v 1.32 2006/07/23 13:16:31 vanbaal Exp $ =head1 COPYRIGHT Copyright (C) 2002 Stichting LogReport Foundation LogReport@LogReport.org This file is part of Lire. Lire is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program (see COPYING); if not, check with http://www.gnu.org/copyleft/gpl.html. =head1 AUTHOR Francis J. Lacoste =cut