View | Details | Raw Unified | Return to bug 24228
Collapse All | Expand All

(-)a/Koha/Object.pm (-23 / +66 lines)
Lines 22-28 use Modern::Perl; Link Here
22
22
23
use Carp;
23
use Carp;
24
use Mojo::JSON;
24
use Mojo::JSON;
25
use Scalar::Util qw( looks_like_number );
25
use Scalar::Util qw( blessed looks_like_number );
26
use Try::Tiny;
26
use Try::Tiny;
27
27
28
use Koha::Database;
28
use Koha::Database;
Lines 374-387 sub _numeric_column_type { Link Here
374
374
375
=head3 to_api
375
=head3 to_api
376
376
377
    my $object_for_api = $object->to_api;
377
    my $object_for_api = $object->to_api(
378
        {
379
          [ embed => {
380
                items => {
381
                    children => {
382
                        holds => {,
383
                            children => {
384
                              ...
385
                            }
386
                        }
387
                    }
388
                },
389
                library => {
390
                    ...
391
                }
392
            },
393
            ...
394
         ]
395
        }
396
    );
378
397
379
Returns a representation of the object, suitable for API output.
398
Returns a representation of the object, suitable for API output.
380
399
381
=cut
400
=cut
382
401
383
sub to_api {
402
sub to_api {
384
    my ( $self, $embeds ) = @_;
403
    my ( $self, $params ) = @_;
385
    my $json_object = $self->TO_JSON;
404
    my $json_object = $self->TO_JSON;
386
405
387
    my $to_api_mapping = $self->to_api_mapping;
406
    my $to_api_mapping = $self->to_api_mapping;
Lines 405-440 sub to_api { Link Here
405
        }
424
        }
406
    }
425
    }
407
426
408
    if ($embeds) {
427
    my $embeds = $params->{embed};
409
        foreach my $embed (@$embeds) {
410
            my ( $curr, $next ) = split /\s*\.\s*/, $embed, 2;
411
            my @nxembeds;
412
428
413
            @nxembeds = ($next) if $next;
429
    if ($embeds) {
430
        foreach my $embed ( keys %{$embeds} ) {
431
            my $curr = $embed;
432
            my $next = $embeds->{$curr}->{children};
414
433
415
            my $children = $self->$curr;
434
            my $children = $self->$curr;
416
            if ( ref $children eq 'ARRAY' ) {
435
417
                my @list;
436
            if ( defined $children and ref($children) eq 'ARRAY' ) {
418
                my $pos = 0;
437
                my @list = map {
419
                foreach my $child (@$children) {
438
                    $self->_handle_to_api_child(
420
                    my $res = $child->to_api( \@nxembeds );
439
                        { child => $_, next => $next, curr => $curr } )
421
                    $res = { $json_object->{$curr}->[$pos], $res }
440
                } @{$children};
422
                      if defined $json_object->{$curr}
423
                      && defined $json_object->{$curr}->[$pos];
424
                    push @list, $res;
425
                    $pos++;
426
                }
427
                $json_object->{$curr} = \@list;
441
                $json_object->{$curr} = \@list;
428
            }
442
            }
429
            else {
443
            else {
430
                my $res = $children->to_api( \@nxembeds );
444
                $json_object->{$curr} = $self->_handle_to_api_child(
431
                $res = { $json_object->{$curr}, $res }
445
                    { child => $children, next => $next, curr => $curr } );
432
                  if defined $json_object->{$curr};
433
                $json_object->{$curr} = $res;
434
            }
446
            }
435
        }
447
        }
436
    }
448
    }
437
449
450
451
438
    return $json_object;
452
    return $json_object;
439
}
453
}
440
454
Lines 667-672 For example, for borrowers, the _type method will return "Borrower". Link Here
667
681
668
sub _type { }
682
sub _type { }
669
683
684
=head3 _handle_to_api_child
685
686
=cut
687
688
sub _handle_to_api_child {
689
    my ($self, $args ) = @_;
690
691
    my $child = $args->{child};
692
    my $next  = $args->{next};
693
    my $curr  = $args->{curr};
694
695
    my $res;
696
697
    if ( defined $child ) {
698
699
        Koha::Exceptions::Exception->throw( "Asked to embed $curr but its return value doesn't implement to_api" )
700
            if defined $next and blessed $child and !$child->can('to_api');
701
702
        if ( blessed $child ) {
703
            $res = $child->to_api({ embed => $next });
704
        }
705
        else {
706
            $res = $child;
707
        }
708
    }
709
710
    return $res;
711
}
712
670
sub DESTROY { }
713
sub DESTROY { }
671
714
672
=head1 AUTHOR
715
=head1 AUTHOR
(-)a/Koha/Objects.pm (-2 / +2 lines)
Lines 315-323 Returns a representation of the objects, suitable for API output . Link Here
315
=cut
315
=cut
316
316
317
sub to_api {
317
sub to_api {
318
    my ($self, $embeds) = @_;
318
    my ($self, $params) = @_;
319
319
320
    return [ map { $_->to_api($embeds) } $self->as_list ];
320
    return [ map { $_->to_api($params) } $self->as_list ];
321
}
321
}
322
322
323
=head3 Koha::Objects->_wrap
323
=head3 Koha::Objects->_wrap
(-)a/t/db_dependent/Koha/Object.t (-23 / +53 lines)
Lines 215-221 subtest 'TO_JSON tests' => sub { Link Here
215
215
216
subtest "to_api() tests" => sub {
216
subtest "to_api() tests" => sub {
217
217
218
    plan tests => 18;
218
    plan tests => 26;
219
219
220
    $schema->storage->txn_begin;
220
    $schema->storage->txn_begin;
221
221
Lines 262-304 subtest "to_api() tests" => sub { Link Here
262
    my $illrequest = $builder->build_object({ class => 'Koha::Illrequests' });
262
    my $illrequest = $builder->build_object({ class => 'Koha::Illrequests' });
263
    is_deeply( $illrequest->to_api, $illrequest->TO_JSON, 'If no overloaded to_api_mapping method, return TO_JSON' );
263
    is_deeply( $illrequest->to_api, $illrequest->TO_JSON, 'If no overloaded to_api_mapping method, return TO_JSON' );
264
264
265
    my $item_class = Test::MockModule->new('Koha::Item');
266
    $item_class->mock( 'to_api_mapping',
267
        sub {
268
            return {
269
                itemnumber       => 'item_id'
270
            };
271
        }
272
    );
273
274
    my $hold_class = Test::MockModule->new('Koha::Hold');
275
    $hold_class->mock( 'to_api_mapping',
276
        sub {
277
            return {
278
                reserve_id       => 'hold_id'
279
            };
280
        }
281
    );
282
283
    my $biblio = $builder->build_sample_biblio();
265
    my $biblio = $builder->build_sample_biblio();
284
    my $item = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
266
    my $item = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
285
    my $hold = $builder->build_object({ class => 'Koha::Holds', value => { itemnumber => $item->itemnumber } });
267
    my $hold = $builder->build_object({ class => 'Koha::Holds', value => { itemnumber => $item->itemnumber } });
286
268
287
    my @embeds = ('items');
269
    my $embeds = { 'items' => {} };
288
270
289
    my $biblio_api = $biblio->to_api(\@embeds);
271
    my $biblio_api = $biblio->to_api({ embed => $embeds });
290
272
291
    ok(exists $biblio_api->{items}, 'Items where embedded in biblio results');
273
    ok(exists $biblio_api->{items}, 'Items where embedded in biblio results');
292
    is($biblio_api->{items}->[0]->{item_id}, $item->itemnumber, 'Item matches');
274
    is($biblio_api->{items}->[0]->{item_id}, $item->itemnumber, 'Item matches');
293
    ok(!exists $biblio_api->{items}->[0]->{holds}, 'No holds info should be embedded yet');
275
    ok(!exists $biblio_api->{items}->[0]->{holds}, 'No holds info should be embedded yet');
294
276
295
    @embeds = ('items.holds');
277
    $embeds = (
296
    $biblio_api = $biblio->to_api(\@embeds);
278
        {
279
            'items' => {
280
                'children' => {
281
                    'holds' => {}
282
                }
283
            },
284
            'biblioitem' => {}
285
        }
286
    );
287
    $biblio_api = $biblio->to_api({ embed => $embeds });
297
288
298
    ok(exists $biblio_api->{items}, 'Items where embedded in biblio results');
289
    ok(exists $biblio_api->{items}, 'Items where embedded in biblio results');
299
    is($biblio_api->{items}->[0]->{item_id}, $item->itemnumber, 'Item still matches');
290
    is($biblio_api->{items}->[0]->{item_id}, $item->itemnumber, 'Item still matches');
300
    ok(exists $biblio_api->{items}->[0]->{holds}, 'Holds info should be embedded');
291
    ok(exists $biblio_api->{items}->[0]->{holds}, 'Holds info should be embedded');
301
    is($biblio_api->{items}->[0]->{holds}->[0]->{hold_id}, $hold->reserve_id, 'Hold matches');
292
    is($biblio_api->{items}->[0]->{holds}->[0]->{hold_id}, $hold->reserve_id, 'Hold matches');
293
    is_deeply($biblio_api->{biblioitem}, $biblio->biblioitem->to_api, 'More than one root');
294
295
    my $hold_api = $hold->to_api(
296
        {
297
            embed => { 'item' => {} }
298
        }
299
    );
300
301
    is( ref($hold_api->{item}), 'HASH', 'Single nested object works correctly' );
302
    is( $hold_api->{item}->{item_id}, $item->itemnumber, 'Object embedded correctly' );
303
304
    # biblio with no items
305
    my $new_biblio = $builder->build_sample_biblio;
306
    my $new_biblio_api = $new_biblio->to_api({ embed => $embeds });
307
308
    is_deeply( $new_biblio_api->{items}, [], 'Empty list if no items' );
309
310
    my $biblio_class = Test::MockModule->new('Koha::Biblio');
311
    $biblio_class->mock( 'undef_result', sub { return; } );
312
313
    $new_biblio_api = $new_biblio->to_api({ embed => ( { 'undef_result' => {} } ) });
314
    ok( exists $new_biblio_api->{undef_result}, 'If a method returns undef, then the attribute is defined' );
315
    is( $new_biblio_api->{undef_result}, undef, 'If a method returns undef, then the attribute is undef' );
316
317
    $biblio_class->mock( 'items',
318
        sub { return [ bless { itemnumber => 1 }, 'Somethings' ]; } );
319
320
    throws_ok {
321
        $new_biblio_api = $new_biblio->to_api(
322
            { embed => { 'items' => { children => { asd => {} } } } } );
323
    }
324
    'Koha::Exceptions::Exception',
325
"An exception is thrown if a blessed object to embed doesn't implement to_api";
326
327
    is(
328
        "$@",
329
        "Asked to embed items but its return value doesn't implement to_api",
330
        "Exception message correct"
331
    );
302
332
303
    $schema->storage->txn_rollback;
333
    $schema->storage->txn_rollback;
304
};
334
};
(-)a/t/db_dependent/Koha/Objects.t (-2 / +64 lines)
Lines 283-289 subtest '->search() tests' => sub { Link Here
283
283
284
subtest "to_api() tests" => sub {
284
subtest "to_api() tests" => sub {
285
285
286
    plan tests => 4;
286
    plan tests => 18;
287
287
288
    $schema->storage->txn_begin;
288
    $schema->storage->txn_begin;
289
289
Lines 303-308 subtest "to_api() tests" => sub { Link Here
303
    is_deeply( $cities_api->[0], $city_1->to_api, 'to_api returns the individual objects with ->to_api' );
303
    is_deeply( $cities_api->[0], $city_1->to_api, 'to_api returns the individual objects with ->to_api' );
304
    is_deeply( $cities_api->[1], $city_2->to_api, 'to_api returns the individual objects with ->to_api' );
304
    is_deeply( $cities_api->[1], $city_2->to_api, 'to_api returns the individual objects with ->to_api' );
305
305
306
    my $biblio_1 = $builder->build_sample_biblio();
307
    my $item_1   = $builder->build_sample_item({ biblionumber => $biblio_1->biblionumber });
308
    my $hold_1   = $builder->build_object(
309
        {
310
            class => 'Koha::Holds',
311
            value => { itemnumber => $item_1->itemnumber }
312
        }
313
    );
314
315
    my $biblio_2 = $builder->build_sample_biblio();
316
    my $item_2   = $builder->build_sample_item({ biblionumber => $biblio_2->biblionumber });
317
    my $hold_2   = $builder->build_object(
318
        {
319
            class => 'Koha::Holds',
320
            value => { itemnumber => $item_2->itemnumber }
321
        }
322
    );
323
324
    my $embed = { 'items' => {} };
325
326
    my $i = 0;
327
    my @items = ( $item_1, $item_2 );
328
    my @holds = ( $hold_1, $hold_2 );
329
330
    my $biblios_api = Koha::Biblios->search(
331
        {
332
            biblionumber => [ $biblio_1->biblionumber, $biblio_2->biblionumber ]
333
        }
334
    )->to_api( { embed => $embed } );
335
336
    foreach my $biblio_api ( @{ $biblios_api } ) {
337
        ok(exists $biblio_api->{items}, 'Items where embedded in biblio results');
338
        is($biblio_api->{items}->[0]->{item_id}, $items[$i]->itemnumber, 'Item matches');
339
        ok(!exists $biblio_api->{items}->[0]->{holds}, 'No holds info should be embedded yet');
340
341
        $i++;
342
    }
343
344
    # One more level
345
    $embed = {
346
        'items' => {
347
            children => { 'holds' => {} }
348
        }
349
    };
350
351
    $i = 0;
352
353
    $biblios_api = Koha::Biblios->search(
354
        {
355
            biblionumber => [ $biblio_1->biblionumber, $biblio_2->biblionumber ]
356
        }
357
    )->to_api( { embed => $embed } );
358
359
    foreach my $biblio_api ( @{ $biblios_api } ) {
360
361
        ok(exists $biblio_api->{items}, 'Items where embedded in biblio results');
362
        is($biblio_api->{items}->[0]->{item_id}, $items[$i]->itemnumber, 'Item still matches');
363
        ok(exists $biblio_api->{items}->[0]->{holds}, 'Holds info should be embedded');
364
        is($biblio_api->{items}->[0]->{holds}->[0]->{hold_id}, $holds[$i]->reserve_id, 'Hold matches');
365
366
        $i++;
367
    }
368
306
    $schema->storage->txn_rollback;
369
    $schema->storage->txn_rollback;
307
};
370
};
308
371
309
- 

Return to bug 24228