From fb464e6ef9cff3fbb06d9f8197c6233b13c9a907 Mon Sep 17 00:00:00 2001 From: Lari Taskula Date: Thu, 4 Feb 2021 19:28:30 +0000 Subject: [PATCH] Bug 20028: Add Koha::Patron->export The logic behind gathering related data relies on DBIx relationships to Borrower source. This patch does not care about terminology - it returns related data in a hashref containing keys of DBIx source class names, such as Borrower. To test: 1. prove t/db_dependent/Koha/Patron.t 2. Observe success Sponsored-by: The National Library of Finland --- Koha/Patron.pm | 82 +++++++++++++++++++++++++++ t/db_dependent/Koha/Patron.t | 106 ++++++++++++++++++++++++++++++++++- 2 files changed, 187 insertions(+), 1 deletion(-) diff --git a/Koha/Patron.pm b/Koha/Patron.pm index 6ea9e5aae7..e335c25572 100644 --- a/Koha/Patron.pm +++ b/Koha/Patron.pm @@ -1536,6 +1536,88 @@ sub add_extended_attribute { return Koha::Patron::Attribute->new($attribute)->store; } +=head3 export + + my $export = $patron->export() + + Gathers patron's related data. Works by checking DBIx relationships to + Borrower. + + Returns a HASHref containing keys of DBIx source names, e.g. + + { + "Accountline": [ + { "accountline_id": 1, "borrowernumber": 1481, ... }, + { "accountline_id": 2, "borrowernumber": 1481, ... } + ], + "Borrower": { "borrowernumber": 1481, "firstname": "Export", ... }, + ..., + "Virtualshelve": [ + { "shelfnumber": 1, "owner": 1481, ... }, + { "shelfnumber": 2, "owner": 1481, ... } + ] + } + +=cut + +sub export { + my ( $self ) = @_; + + my $export = {}; + + my $logger = Koha::Logger->get; + my $result_source = $self->_result()->result_source; + + foreach my $rel ( $self->_result()->relationships() ) { + my $related_source = $result_source->related_source( $rel ); + + # Skip all the "[borrower] belongs_to" relationships + my $info = $result_source->relationship_info( $rel ); + if ( $info->{'attrs'}->{'is_depends_on'} ) { + next; + } + + my $src_name = $related_source->source_name; + + # 'cond' has format foreign.columnname, remove ^foreign. from it + ( my $rel_col = ( keys %{$info->{'cond'}} )[0] ) =~ s/^foreign\.//; + + my $rs = $related_source->resultset; + my $res = $rs->search( { $rel_col => $self->borrowernumber } ); + + $res->result_class('DBIx::Class::ResultClass::HashRefInflator'); + + unless ( exists $export->{$src_name} ) { + $export->{$src_name} = []; + } + + foreach my $obj ( $res->all() ) { + # Check if object already exists in return array + my $already_present = 0; + my $ddsk = $Data::Dumper::Sortkeys; + $Data::Dumper::Sortkeys = 1; # sort keys temporarily + foreach my $already_existing ( @{ $export->{$src_name} } ) { + + if ( Data::Dumper::Dumper( $already_existing ) + eq Data::Dumper::Dumper( $obj )) + { + $already_present = 1; + last; + } + } + $Data::Dumper::Sortkeys = $ddsk; # restore previous value + + next if $already_present; + + push @{ $export->{$src_name} }, $obj; + } + } + + $export->{'Borrower'} = $self->unblessed; + + return $export; +} + =head3 extended_attributes Return object of Koha::Patron::Attributes type with all attributes set for this patron diff --git a/t/db_dependent/Koha/Patron.t b/t/db_dependent/Koha/Patron.t index 1b0d24552a..cbcc6005d8 100755 --- a/t/db_dependent/Koha/Patron.t +++ b/t/db_dependent/Koha/Patron.t @@ -19,7 +19,7 @@ use Modern::Perl; -use Test::More tests => 6; +use Test::More tests => 7; use Test::Exception; use Koha::Database; @@ -77,6 +77,110 @@ subtest 'add_guarantor() tests' => sub { $schema->storage->txn_rollback; }; +subtest 'export' => sub { + + my @related_sources = _get_related_sources(); + plan tests => scalar @related_sources * 2; + + $schema->storage->txn_begin; + + my $patron = $builder->build_object( + { + class => 'Koha::Patrons', + } + ); + + my $test_objects = { + 'Borrower' => $patron->unblessed, + }; + + my $limit_data = 5; # build this many random test objects + my $generated_data = 0; + + foreach my $src ( @related_sources ) { + next if $src eq 'Borrower'; # Borrower is a hashref, + $test_objects->{$src} = []; # the others are arrayrefs + } + + my $result_source = Koha::Patron->new->_result()->result_source; + foreach my $rel ( Koha::Patron->new->_result()->relationships() ) { + if ($generated_data >= $limit_data) { + last; + } + + my $related_source = $result_source->related_source( $rel ); + my $source_name = $related_source->source_name; + + my $info = $result_source->relationship_info( $rel ); + + # We are not interested in the "belongs_to" relationship of borrowers. + # These are tables like branches, categories and sms_provider. + if ( $info->{'attrs'}->{'is_depends_on'} ) { + next; + } + + ( my $rel_col = (keys %{$info->{'cond'}})[0] ) =~ s/^foreign\.//; + + # Generate test data into related tables + my $built; + if ( $related_source->result_class->can('koha_objects_class') ) { + $built = $builder->build_object( + { + class => $related_source->result_class->koha_objects_class, + value => { $rel_col => $patron->borrowernumber } + } + ); + $built = $built->unblessed; + } else { + $built = $builder->build( + { + source => $source_name, + value => { $rel_col => $patron->borrowernumber } + } + ); + } + push @{ $test_objects->{$related_source->source_name} }, $built; + $generated_data++; + } + + # Generate test data into a random table. Just one because test data + # generation takes so long. + $builder->build( { + source => (keys %$test_objects)[rand keys %$test_objects] + } ); + + my $export = $patron->export; + + foreach my $rel ( @related_sources ) { + my $related_source = $schema->source( $rel ); + my $src_name = $related_source->source_name; + + ok( exists $export->{$src_name}, "$src_name exists in export" ); + is_deeply( + $export->{$src_name}, + $test_objects->{$src_name}, + "$src_name export data matches built test data" + ); + } + + sub _get_related_sources { + my $sources = {}; + my $res_source = Koha::Patron->new->_result()->result_source; + foreach my $rel ( Koha::Patron->new->_result()->relationships() ) { + my $related_source = $res_source->related_source($rel); + my $info = $res_source->relationship_info( $rel ); + next if $info->{'attrs'}->{'is_depends_on'}; + next if $sources->{$related_source->source_name}; + $sources->{$related_source->source_name} = 1; + } + $sources->{'Borrower'} = 1; # add Borrower itself + my @sorted = sort keys %$sources; + return @sorted; + } + + $schema->storage->txn_rollback; +}; + subtest 'relationships_debt() tests' => sub { plan tests => 168; -- 2.25.1