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 373-386 sub _numeric_column_type { Link Here
373
373
374
=head3 to_api
374
=head3 to_api
375
375
376
    my $object_for_api = $object->to_api;
376
    my $object_for_api = $object->to_api(
377
        {
378
          [ embed => {
379
                items => {
380
                    children => {
381
                        holds => {,
382
                            children => {
383
                              ...
384
                            }
385
                        }
386
                    }
387
                },
388
                library => {
389
                    ...
390
                }
391
            },
392
            ...
393
         ]
394
        }
395
    );
377
396
378
Returns a representation of the object, suitable for API output.
397
Returns a representation of the object, suitable for API output.
379
398
380
=cut
399
=cut
381
400
382
sub to_api {
401
sub to_api {
383
    my ( $self, $embeds ) = @_;
402
    my ( $self, $params ) = @_;
384
    my $json_object = $self->TO_JSON;
403
    my $json_object = $self->TO_JSON;
385
404
386
    my $to_api_mapping = $self->to_api_mapping;
405
    my $to_api_mapping = $self->to_api_mapping;
Lines 404-439 sub to_api { Link Here
404
        }
423
        }
405
    }
424
    }
406
425
407
    if ($embeds) {
426
    my $embeds = $params->{embed};
408
        foreach my $embed (@$embeds) {
409
            my ( $curr, $next ) = split /\s*\.\s*/, $embed, 2;
410
            my @nxembeds;
411
427
412
            @nxembeds = ($next) if $next;
428
    if ($embeds) {
429
        foreach my $embed ( keys %{$embeds} ) {
430
            my $curr = $embed;
431
            my $next = $embeds->{$curr}->{children};
413
432
414
            my $children = $self->$curr;
433
            my $children = $self->$curr;
415
            if ( ref $children eq 'ARRAY' ) {
434
416
                my @list;
435
            if ( defined $children and ref($children) eq 'ARRAY' ) {
417
                my $pos = 0;
436
                my @list = map {
418
                foreach my $child (@$children) {
437
                    $self->_handle_to_api_child(
419
                    my $res = $child->to_api( \@nxembeds );
438
                        { child => $_, next => $next, curr => $curr } )
420
                    $res = { $json_object->{$curr}->[$pos], $res }
439
                } @{$children};
421
                      if defined $json_object->{$curr}
422
                      && defined $json_object->{$curr}->[$pos];
423
                    push @list, $res;
424
                    $pos++;
425
                }
426
                $json_object->{$curr} = \@list;
440
                $json_object->{$curr} = \@list;
427
            }
441
            }
428
            else {
442
            else {
429
                my $res = $children->to_api( \@nxembeds );
443
                $json_object->{$curr} = $self->_handle_to_api_child(
430
                $res = { $json_object->{$curr}, $res }
444
                    { child => $children, next => $next, curr => $curr } );
431
                  if defined $json_object->{$curr};
432
                $json_object->{$curr} = $res;
433
            }
445
            }
434
        }
446
        }
435
    }
447
    }
436
448
449
450
437
    return $json_object;
451
    return $json_object;
438
}
452
}
439
453
Lines 666-671 For example, for borrowers, the _type method will return "Borrower". Link Here
666
680
667
sub _type { }
681
sub _type { }
668
682
683
=head3 _handle_to_api_child
684
685
=cut
686
687
sub _handle_to_api_child {
688
    my ($self, $args ) = @_;
689
690
    my $child = $args->{child};
691
    my $next  = $args->{next};
692
    my $curr  = $args->{curr};
693
694
    my $res;
695
696
    if ( defined $child ) {
697
698
        Koha::Exceptions::Exception->throw( "Asked to embed $curr but its return value doesn't implement to_api" )
699
            if defined $next and blessed $child and !$child->can('to_api');
700
701
        if ( blessed $child ) {
702
            $res = $child->to_api({ embed => $next });
703
        }
704
        else {
705
            $res = $child;
706
        }
707
    }
708
709
    return $res;
710
}
711
669
sub DESTROY { }
712
sub DESTROY { }
670
713
671
=head1 AUTHOR
714
=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