@@ -, +, @@ { embed => [ { accessor => 'items', children => [ ... ] } ] } $ kshell k$ prove t/db_dependent/Koha/Object.t t/db_dependent/Koha/Objects.t --- Koha/Object.pm | 34 ++++++++++++---- Koha/Objects.pm | 4 +- t/db_dependent/Koha/Object.t | 36 ++++++++++++++--- t/db_dependent/Koha/Objects.t | 73 ++++++++++++++++++++++++++++++++++- 4 files changed, 132 insertions(+), 15 deletions(-) --- a/Koha/Object.pm +++ a/Koha/Object.pm @@ -373,16 +373,35 @@ sub _numeric_column_type { =head3 to_api - my $object_for_api = $object->to_api; + my $object_for_api = $object->to_api( + { + [ embed => [ + { + accessor => 'items', + children => [ + { + accessor => 'holds, + children => [ + ... + ] + } + ] + }, + ... + ] ] + } + ); Returns a representation of the object, suitable for API output. =cut sub to_api { - my ( $self, $embeds ) = @_; + my ( $self, $params ) = @_; my $json_object = $self->TO_JSON; + my $embeds = $params->{embed}; + # Rename attributes if there's a mapping if ( $self->can('to_api_mapping') ) { foreach my $column ( keys %{ $self->to_api_mapping } ) { @@ -404,17 +423,18 @@ sub to_api { if ($embeds) { foreach my $embed (@$embeds) { - my ( $curr, $next ) = split /\s*\.\s*/, $embed, 2; - my @nxembeds; + my $curr = $embed->{accessor}; + my $next = $embed->{children}; - @nxembeds = ($next) if $next; + my @nxembeds; + @nxembeds = @{ $next } if $next; my $children = $self->$curr; if ( ref $children eq 'ARRAY' ) { my @list; my $pos = 0; foreach my $child (@$children) { - my $res = $child->to_api( \@nxembeds ); + my $res = $child->to_api({ embed => \@nxembeds }); $res = { $json_object->{$curr}->[$pos], $res } if defined $json_object->{$curr} && defined $json_object->{$curr}->[$pos]; @@ -424,7 +444,7 @@ sub to_api { $json_object->{$curr} = \@list; } else { - my $res = $children->to_api( \@nxembeds ); + my $res = $children->to_api({ embed => \@nxembeds }); $res = { $json_object->{$curr}, $res } if defined $json_object->{$curr}; $json_object->{$curr} = $res; --- a/Koha/Objects.pm +++ a/Koha/Objects.pm @@ -315,9 +315,9 @@ Returns a representation of the objects, suitable for API output . =cut sub to_api { - my ($self, $embeds) = @_; + my ($self, $params) = @_; - return [ map { $_->to_api($embeds) } $self->as_list ]; + return [ map { $_->to_api($params) } $self->as_list ]; } =head3 Koha::Objects->_wrap --- a/t/db_dependent/Koha/Object.t +++ a/t/db_dependent/Koha/Object.t @@ -215,7 +215,7 @@ subtest 'TO_JSON tests' => sub { subtest "to_api() tests" => sub { - plan tests => 18; + plan tests => 20; $schema->storage->txn_begin; @@ -284,22 +284,48 @@ subtest "to_api() tests" => sub { my $item = $builder->build_sample_item({ biblionumber => $biblio->biblionumber }); my $hold = $builder->build_object({ class => 'Koha::Holds', value => { itemnumber => $item->itemnumber } }); - my @embeds = ('items'); + my @embeds = ( + { + accessor => 'items' + } + ); - my $biblio_api = $biblio->to_api(\@embeds); + my $biblio_api = $biblio->to_api({ embed => \@embeds }); ok(exists $biblio_api->{items}, 'Items where embedded in biblio results'); is($biblio_api->{items}->[0]->{item_id}, $item->itemnumber, 'Item matches'); ok(!exists $biblio_api->{items}->[0]->{holds}, 'No holds info should be embedded yet'); - @embeds = ('items.holds'); - $biblio_api = $biblio->to_api(\@embeds); + @embeds = ( + { + accessor => 'items', + children => [ + { + accessor => 'holds' + } + ] + } + ); + $biblio_api = $biblio->to_api({ embed => \@embeds }); ok(exists $biblio_api->{items}, 'Items where embedded in biblio results'); is($biblio_api->{items}->[0]->{item_id}, $item->itemnumber, 'Item still matches'); ok(exists $biblio_api->{items}->[0]->{holds}, 'Holds info should be embedded'); is($biblio_api->{items}->[0]->{holds}->[0]->{hold_id}, $hold->reserve_id, 'Hold matches'); + my $hold_api = $hold->to_api( + { + embed => [ + { + accessor => 'item' + } + ] + } + ); + + is( ref($hold_api->{item}), 'HASH', 'Single nested object works correctly' ); + is( $hold_api->{item}->{item_id}, $item->itemnumber, 'Object embedded correctly' ); + $schema->storage->txn_rollback; }; --- a/t/db_dependent/Koha/Objects.t +++ a/t/db_dependent/Koha/Objects.t @@ -283,7 +283,7 @@ subtest '->search() tests' => sub { subtest "to_api() tests" => sub { - plan tests => 4; + plan tests => 18; $schema->storage->txn_begin; @@ -303,6 +303,77 @@ subtest "to_api() tests" => sub { is_deeply( $cities_api->[0], $city_1->to_api, 'to_api returns the individual objects with ->to_api' ); is_deeply( $cities_api->[1], $city_2->to_api, 'to_api returns the individual objects with ->to_api' ); + my $biblio_1 = $builder->build_sample_biblio(); + my $item_1 = $builder->build_sample_item({ biblionumber => $biblio_1->biblionumber }); + my $hold_1 = $builder->build_object( + { + class => 'Koha::Holds', + value => { itemnumber => $item_1->itemnumber } + } + ); + + my $biblio_2 = $builder->build_sample_biblio(); + my $item_2 = $builder->build_sample_item({ biblionumber => $biblio_2->biblionumber }); + my $hold_2 = $builder->build_object( + { + class => 'Koha::Holds', + value => { itemnumber => $item_2->itemnumber } + } + ); + + my @embed = ( + { + accessor => 'items' + } + ); + + my $i = 0; + my @items = ( $item_1, $item_2 ); + my @holds = ( $hold_1, $hold_2 ); + + my $biblios_api = Koha::Biblios->search( + { + biblionumber => [ $biblio_1->biblionumber, $biblio_2->biblionumber ] + } + )->to_api( { embed => \@embed } ); + + foreach my $biblio_api ( @{ $biblios_api } ) { + ok(exists $biblio_api->{items}, 'Items where embedded in biblio results'); + is($biblio_api->{items}->[0]->{item_id}, $items[$i]->itemnumber, 'Item matches'); + ok(!exists $biblio_api->{items}->[0]->{holds}, 'No holds info should be embedded yet'); + + $i++; + } + + # One more level + @embed = ( + { + accessor => 'items', + children => [ + { + accessor => 'holds' + } + ] + } + ); + $i = 0; + + $biblios_api = Koha::Biblios->search( + { + biblionumber => [ $biblio_1->biblionumber, $biblio_2->biblionumber ] + } + )->to_api( { embed => \@embed } ); + + foreach my $biblio_api ( @{ $biblios_api } ) { + + ok(exists $biblio_api->{items}, 'Items where embedded in biblio results'); + is($biblio_api->{items}->[0]->{item_id}, $items[$i]->itemnumber, 'Item still matches'); + ok(exists $biblio_api->{items}->[0]->{holds}, 'Holds info should be embedded'); + is($biblio_api->{items}->[0]->{holds}->[0]->{hold_id}, $holds[$i]->reserve_id, 'Hold matches'); + + $i++; + } + $schema->storage->txn_rollback; }; --