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   2611139 use Moose;
  23         5665479  
  23         156  
5              
6 23     23   171948 use PONAPI::Builder::Resource;
  23         79  
  23         962  
7 23     23   16715 use PONAPI::Builder::Resource::Null;
  23         688  
  23         831  
8 23     23   14461 use PONAPI::Builder::Errors;
  23         86  
  23         23690  
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   3849 sub _build_errors_builder { PONAPI::Builder::Errors->new( parent => $_[0] ) }
90              
91 28     28 0 1354 sub convert_to_collection { $_[0]->_set_is_collection(1) }
92              
93             sub has_errors {
94 137     137 0 236 my $self = shift;
95 137 100 66     6744 return $self->errors_builder->has_errors
96             if $self->has_errors_builder and $self->errors_builder->has_errors;
97 25         1488 return 0;
98             }
99              
100             sub has_resource {
101 172     172 0 1748 my $self = shift;
102 172 100       9128 $self->has_resource_builders && $self->_num_resource_builders > 0;
103             }
104              
105             sub has_resources {
106 5     5 0 11 my $self = shift;
107 5 100       275 $self->has_resource_builders && $self->_num_resource_builders > 1;
108             }
109              
110             sub add_resource {
111 107     107 0 1653 my ($self, %args) = @_;
112              
113 107 100 100     455 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         5185 my $builder = PONAPI::Builder::Resource->new( %args, parent => $self );
117 106         6586 $self->_add_resource_builder( $builder );
118 106         470 return $builder;
119             }
120              
121             sub add_null_resource {
122 7     7 0 473 my $self = shift;
123              
124 7         344 my $builder = PONAPI::Builder::Resource::Null->new( parent => $self );
125 7         393 $self->_add_resource_builder( $builder );
126 7         22 return $builder;
127             }
128              
129             sub add_included {
130 27     27 0 655 my ($self, %args) = @_;
131 27         1240 my $builder = PONAPI::Builder::Resource->new( parent => $self, %args );
132 27         1415 $self->_add_included( $builder );
133 27         126 return $builder;
134             }
135              
136             sub add_self_link {
137 28     28 0 53 my $self = shift;
138 28         1158 $self->links_builder->add_link( self => $self->req_path );
139 28         84 return $self;
140             }
141              
142             sub build {
143 227     227 0 4367 my $self = shift;
144 227         541 my %args = @_;
145 227         9293 my $result = +{ jsonapi => { version => $self->version } };
146              
147 227 100       11211 if ( ! $self->has_errors_builder ) {
148 117 100       6194 $result->{meta} = $self->_meta if $self->has_meta;
149 117 100       6398 $result->{links} = $self->links_builder->build if $self->has_links_builder;
150              
151 117 100       6027 if ( $self->has_resource_builders ) {
152 88 100       3910 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         263  
  29         1216  
156             }
157             else {
158             # if it is a single resource,
159             # just use that one
160 59 50       240 $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       4760 if ( $self->has_included ) {
170 13         519 my $included_builders = $self->_included;
171 13         33 my (@included, %seen);
172 13         43 foreach my $builder ( @$included_builders ) {
173 26 100       157 next if $seen{$builder->{type}}{$builder->{id}}++;
174 25         102 push @included, $builder->build( %args );
175             }
176 13         81 $result->{included} = \@included;
177             }
178             }
179             else {
180 29 100       1376 if ( $self->is_collection ) {
181 3         10 $result->{data} = [];
182             }
183             else {
184 26 100       1385 die "[PANIC] OH NOES, THIS SHOULD NEVER HAPPEN!!!!!"
185             if ! $self->has_meta;
186             }
187             }
188             }
189              
190 226 100       10697 if ( $self->has_errors_builder ) {
191 110         4192 my $errors = $self->errors_builder->build;
192 110 50       318 if ( $errors ) {
193 110   66     3838 $_->{status} //= $self->status for @$errors;
194             }
195             return +{
196 110         4036 jsonapi => +{ version => $self->version },
197             errors => $errors,
198             };
199             }
200              
201 116         973 return $result;
202             }
203              
204             __PACKAGE__->meta->make_immutable;
205 23     23   207 no Moose; 1;
  23         54  
  23         1218  
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.002005
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