JSONAPI-Document

 view release on metacpan or  search on metacpan

lib/JSONAPI/Document/Builder/Compound.pm  view on Meta::CPAN

=cut

sub build_document {
    my ($self) = @_;

    my $document = $self->build();

    my %relationships;
    foreach my $relationship (@{ $self->primary_relationships },
        map { $_ } map { keys(%$_) } @{ $self->nested_relationships })
    {
        my $relationship_type = $self->format_type($relationship);
        $relationships{$relationship_type} = $self->build_relationship($relationship);
    }
    if (values(%relationships)) {
        $document->{relationships} = \%relationships;
    }

    return $document;
}

=head2 build_relationships : ArrayRef

Builds an ArrayRef containing all given relationships.
These relationships are built with their attributes.

=cut

sub build_relationships {
    my ($self, $relationships, $fields) = @_;
    $fields //= {};
    return [] unless $relationships;

    if (ref($relationships) ne 'ARRAY') {
        Carp::confess('Invalid request: relationships must be an array ref.');
    }

    return [] unless @$relationships;

    my @included;

    foreach my $relation (sort @{ $self->primary_relationships }) {
        my $result = $self->build_relationship($relation, $fields->{$relation}, { with_attributes => 1 });
        if (my $related_docs = $result->{data}) {
            if (ref($related_docs) eq 'ARRAY') {    # plural relations
                push @included, @$related_docs;
            } else {                                # singular relations
                push @included, $related_docs;
            }
        }
    }

    # Note that this fetches the relationship on $self->row, so it shouldn't be done above.
    foreach my $nested (@{ $self->nested_relationships }) {
        my ($relation_source) = keys(%$nested);
        my $result_ref =
            $self->build_relationship($relation_source, $fields->{$relation_source}, { with_attributes => 1 })->{data};

        if (ref($result_ref) eq 'ARRAY') {  # The source relation is a has_many, link the nested resources for each one.
            my $source_row = $self->row->$relation_source;
            if ($source_row->can('all')) {    # Check if any overlaying dbix resultset class can do "all"
                my $includes =
                    $self->build_nested_from_resultset($source_row, $result_ref, $nested->{$relation_source}, $fields);
                push @included, $_ for @$includes;
            }
        } else {
            my $source_row = $self->row->$relation_source;
            my %relationships;
            foreach my $relationship (@{ $nested->{$relation_source} }) {
                my $relationship_type = $self->format_type($relationship);
                my ($related_data, $includes) = $self->build_nested_relationship(
                    $source_row, $relationship,
                    $fields->{$relationship},
                    { with_attributes => 1 });
                $relationships{$relationship_type} = $related_data;
                push @included, $_ for @$includes;
            }
            if (values(%relationships)) {
                $result_ref->{relationships} = \%relationships;
            }
            push @included, $result_ref;
        }
    }

    return \@included;
}

=head2 build_nested_relationship(Str $primary, Str $relationship, ArrayRef $fields, HashRef $options?) : Array

Uses build_relationship with the rows related resource as
the C<row> argument so the builder can find the relationship.

=cut

sub build_nested_relationship {
    my ($self, $primary_row, $relationship, $fields, $options) = @_;
    $options //= {};
    my $builder = JSONAPI::Document::Builder::Relationships->new({
        api_url          => $self->api_url,
        fields           => $fields,
        kebab_case_attrs => $self->kebab_case_attrs,
        row              => $primary_row,
        relationship     => $relationship,
        with_attributes  => $options->{with_attributes},
    });
    my $document = $builder->build();
    my ($data, $included);
    if (my $doc_data = $document->{data}) {
        if (ref($doc_data) eq 'ARRAY') {
            $data = [];
            foreach my $doc (@$doc_data) {
                push @$data, { id => $doc->{id}, type => $doc->{type} };
                push @$included, $doc;
            }
        } else {
            $data = { id => $doc_data->{id}, type => $doc_data->{type} };
            push @$included, $doc_data;
        }
    }
    return ({ data => $data }, $included);
}



( run in 2.003 seconds using v1.01-cache-2.11-cpan-d8267643d1d )