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 )