File Coverage

blib/lib/PONAPI/Builder/Document.pm
Criterion Covered Total %
statement 68 68 100.0
branch 30 32 93.7
condition 7 9 77.7
subroutine 15 15 100.0
pod 0 9 0.0
total 120 133 90.2


line stmt bran cond sub pod time code
1             # ABSTRACT: document builder class
2             package PONAPI::Builder::Document;
3              
4 23     23   2504450 use Moose;
  23         5695704  
  23         153  
5              
6 23     23   174223 use PONAPI::Builder::Resource;
  23         89  
  23         1024  
7 23     23   17749 use PONAPI::Builder::Resource::Null;
  23         688  
  23         817  
8 23     23   15586 use PONAPI::Builder::Errors;
  23         86  
  23         24560  
9              
10             with 'PONAPI::Builder',
11             'PONAPI::Builder::Role::HasLinksBuilder',
12             'PONAPI::Builder::Role::HasMeta',
13             'PONAPI::Builder::Role::HasPagination';
14              
15             has version => (
16             is => 'ro',
17             isa => 'Str',
18             required => 1,
19             );
20              
21             has status => (
22             init_arg => undef,
23             is => 'ro',
24             isa => 'Num',
25             default => sub { 200 },
26             writer => 'set_status',
27             lazy => 1,
28             predicate => 'has_status',
29             );
30              
31             has req_base => (
32             is => 'ro',
33             isa => 'Str',
34             default => sub { '/' },
35             );
36              
37             has req_path => (
38             is => 'ro',
39             isa => 'Str',
40             default => sub { '/' },
41             );
42              
43             has is_collection => (
44             is => 'ro',
45             writer => '_set_is_collection',
46             isa => 'Bool',
47             default => 0
48             );
49              
50             has _included => (
51             init_arg => undef,
52             traits => [ 'Array' ],
53             is => 'ro',
54             isa => 'ArrayRef[ PONAPI::Builder::Resource ]',
55             lazy => 1,
56             default => sub { +[] },
57             handles => {
58             'has_included' => 'count',
59             # private ...
60             '_add_included' => 'push',
61             }
62             );
63              
64             has _resource_builders => (
65             init_arg => undef,
66             traits => [ 'Array' ],
67             is => 'ro',
68             isa => 'ArrayRef[ PONAPI::Builder::Resource | PONAPI::Builder::Resource::Null ]',
69             lazy => 1,
70             default => sub { +[] },
71             predicate => 'has_resource_builders',
72             handles => {
73             '_num_resource_builders' => 'count',
74             # private ...
75             '_add_resource_builder' => 'push',
76             '_get_resource_builder' => 'get',
77             }
78             );
79              
80             has errors_builder => (
81             init_arg => undef,
82             is => 'ro',
83             isa => 'PONAPI::Builder::Errors',
84             lazy => 1,
85             predicate => 'has_errors_builder',
86             builder => '_build_errors_builder',
87             );
88              
89 99     99   3730 sub _build_errors_builder { PONAPI::Builder::Errors->new( parent => $_[0] ) }
90              
91 28     28 0 1457 sub convert_to_collection { $_[0]->_set_is_collection(1) }
92              
93             sub has_errors {
94 137     137 0 257 my $self = shift;
95 137 100 66     6639 return $self->errors_builder->has_errors
96             if $self->has_errors_builder and $self->errors_builder->has_errors;
97 25         1625 return 0;
98             }
99              
100             sub has_resource {
101 172     172 0 1442 my $self = shift;
102 172 100       9318 $self->has_resource_builders && $self->_num_resource_builders > 0;
103             }
104              
105             sub has_resources {
106 5     5 0 13 my $self = shift;
107 5 100       251 $self->has_resource_builders && $self->_num_resource_builders > 1;
108             }
109              
110             sub add_resource {
111 107     107 0 1559 my ($self, %args) = @_;
112              
113 107 100 100     541 die 'Cannot add more then one resource unless the Document is in collection mode'
114             if $self->has_resource && !$self->is_collection;
115              
116 106         4967 my $builder = PONAPI::Builder::Resource->new( %args, parent => $self );
117 106         6080 $self->_add_resource_builder( $builder );
118 106         492 return $builder;
119             }
120              
121             sub add_null_resource {
122 7     7 0 402 my $self = shift;
123              
124 7         301 my $builder = PONAPI::Builder::Resource::Null->new( parent => $self );
125 7         359 $self->_add_resource_builder( $builder );
126 7         18 return $builder;
127             }
128              
129             sub add_included {
130 27     27 0 651 my ($self, %args) = @_;
131 27         1294 my $builder = PONAPI::Builder::Resource->new( parent => $self, %args );
132 27         1468 $self->_add_included( $builder );
133 27         129 return $builder;
134             }
135              
136             sub add_self_link {
137 28     28 0 51 my $self = shift;
138 28         1127 $self->links_builder->add_link( self => $self->req_path );
139 28         73 return $self;
140             }
141              
142             sub build {
143 227     227 0 3494 my $self = shift;
144 227         554 my %args = @_;
145 227         9165 my $result = +{ jsonapi => { version => $self->version } };
146              
147 227 100       11053 if ( ! $self->has_errors_builder ) {
148 117 100       6096 $result->{meta} = $self->_meta if $self->has_meta;
149 117 100       6374 $result->{links} = $self->links_builder->build if $self->has_links_builder;
150              
151 117 100       6100 if ( $self->has_resource_builders ) {
152 88 100       3669 if ( $self->is_collection ) {
153             # if it is a collection, then
154             # call build on each one ...
155 29         64 $result->{data} = [ map { $_->build( %args ) } @{ $self->_resource_builders } ];
  57         245  
  29         1224  
156             }
157             else {
158             # if it is a single resource,
159             # just use that one
160 59 50       235 $result->{data} = $self->_get_resource_builder(0)->build( %args )
161             if $self->has_resource;
162             }
163              
164              
165             # http://jsonapi.org/format/#document-compound-documents
166             # "A compound document MUST NOT include more than one resource
167             # object for each type and id pair."
168             # So in short, we need to check that we don't have any duplicates.
169 88 100       4839 if ( $self->has_included ) {
170 13         544 my $included_builders = $self->_included;
171 13         35 my (@included, %seen);
172 13         39 foreach my $builder ( @$included_builders ) {
173 26 100       175 next if $seen{$builder->{type}}{$builder->{id}}++;
174 25         104 push @included, $builder->build( %args );
175             }
176 13         82 $result->{included} = \@included;
177             }
178             }
179             else {
180 29 100       1429 if ( $self->is_collection ) {
181 3         11 $result->{data} = [];
182             }
183             else {
184 26 100       1567 die "[PANIC] OH NOES, THIS SHOULD NEVER HAPPEN!!!!!"
185             if ! $self->has_meta;
186             }
187             }
188             }
189              
190 226 100       10794 if ( $self->has_errors_builder ) {
191 110         4059 my $errors = $self->errors_builder->build;
192 110 50       282 if ( $errors ) {
193 110   66     3836 $_->{status} //= $self->status for @$errors;
194             }
195             return +{
196 110         3928 jsonapi => +{ version => $self->version },
197             errors => $errors,
198             };
199             }
200              
201 116         874 return $result;
202             }
203              
204             __PACKAGE__->meta->make_immutable;
205 23     23   221 no Moose; 1;
  23         54  
  23         1312  
206              
207             __END__
208              
209             =pod
210              
211             =encoding UTF-8
212              
213             =head1 NAME
214              
215             PONAPI::Builder::Document - document builder class
216              
217             =head1 VERSION
218              
219             version 0.002006
220              
221             =head1 AUTHORS
222              
223             =over 4
224              
225             =item *
226              
227             Mickey Nasriachi <mickey@cpan.org>
228              
229             =item *
230              
231             Stevan Little <stevan@cpan.org>
232              
233             =item *
234              
235             Brian Fraser <hugmeir@cpan.org>
236              
237             =back
238              
239             =head1 COPYRIGHT AND LICENSE
240              
241             This software is copyright (c) 2016 by Mickey Nasriachi, Stevan Little, Brian Fraser.
242              
243             This is free software; you can redistribute it and/or modify it under
244             the same terms as the Perl 5 programming language system itself.
245              
246             =cut