1package Bread::Board::Service::WithParameters;
2our $AUTHORITY = 'cpan:STEVAN';
3# ABSTRACT: Services with parameters
4$Bread::Board::Service::WithParameters::VERSION = '0.37';
5use Moose::Role;
6use MooseX::Params::Validate qw(validated_hash);
7
8use Bread::Board::Types;
9
10with 'Bread::Board::Service';
11
12has 'parameters' => (
13    traits    => [ 'Hash', 'Copy' ],
14    is        => 'ro',
15    isa       => 'Bread::Board::Service::Parameters',
16    lazy      => 1,
17    coerce    => 1,
18    builder   => '_build_parameters',
19    handles   => {
20        'has_parameters' => 'count'
21    }
22);
23
24has '_parameter_keys_to_remove' => (
25    is        => 'rw',
26    isa       => 'ArrayRef',
27    clearer   => '_clear_parameter_keys_to_remove',
28    predicate => '_has_parameter_keys_to_remove',
29);
30
31before 'get' => sub {
32    my $self = shift;
33    my %params = $self->check_parameters(@_);
34    $self->_parameter_keys_to_remove( [ keys %params ] );
35    $self->params({ %{ $self->params }, %params });
36};
37
38after 'get' => sub {
39    my $self = shift;
40    return unless $self->_has_parameter_keys_to_remove;
41    map { $self->_clear_param( $_ ) } @{ $self->_parameter_keys_to_remove };
42    $self->_clear_parameter_keys_to_remove;
43};
44
45sub _build_parameters { +{} }
46
47sub check_parameters {
48    my $self = shift;
49    return validated_hash(\@_, (
50        %{ $self->parameters },
51        # NOTE:
52        # cache the parameters in a per-service
53        # basis, this should be more than adequate
54        # since each service can only have one set
55        # of parameters at a time. If this does end
56        # up breaking then we can give it a better
57        # key at that point.
58        # - SL
59        (MX_PARAMS_VALIDATE_CACHE_KEY => Scalar::Util::refaddr($self))
60    )) if $self->has_parameters;
61    return ();
62}
63
64sub has_required_parameters {
65    my $self = shift;
66    scalar grep { ! $_->{optional} } values %{ $self->parameters };
67}
68
69sub has_parameter_defaults {
70    my $self = shift;
71    scalar grep { $_->{default} } values %{ $self->parameters };
72}
73
74no Moose::Role; 1;
75
76__END__
77
78=pod
79
80=encoding UTF-8
81
82=head1 NAME
83
84Bread::Board::Service::WithParameters - Services with parameters
85
86=head1 VERSION
87
88version 0.37
89
90=head1 DESCRIPTION
91
92This is a sub-role of L<Bread::Board::Service>, for parameterized
93services. These are services that will instantiate different values
94depending on parameters that are passed to the C<get> method. You can
95pass those parameters via the L<< C<service_params> attribute of
96C<Bread::Board::Dependency>|Bread::Board::Dependency/service_params
97>>, or via the L<< C<inflate> method of
98C<Bread::Board::Service::Deferred::Thunk>|Bread::Board::Service::Deferred::Thunk/inflate
99>>.
100
101=head1 ATTRIBUTES
102
103=head2 C<parameters>
104
105Read-only hashref, will be passed as-is to L<<
106C<MooseX::Params::Validate>'s
107C<validated_hash>|MooseX::Params::Validate/validated_hash >>, so you
108can use things like C<optional> and C<default> in addition to type
109constraints:
110
111  service something => (
112    class => 'Thing',
113    parameters => {
114       type => { isa => 'Str', default => 'text' },
115    },
116  );
117
118This attribute uses coercions on L<<
119C<Bread::Board::Service::Parameters>|Bread::Board::Types/Bread::Board::Service::Parameters
120>> so that you can also say:
121
122  service something => (
123    class => 'Thing',
124    parameters => ['type'],
125  );
126
127and it will be equivalent to:
128
129  service something => (
130    class => 'Thing',
131    parameters => {
132       type => { optional => 0 },
133    },
134  );
135
136=head1 METHODS
137
138=head2 C<has_parameters>
139
140Predicate for the L</parameters> attribute.
141
142=head2 C<has_parameter_defaults>
143
144Returns true if any of the L</parameters> have a C<default> value.
145
146=head2 C<has_required_parameters>
147
148Returns true if any of the L</parameters> does I<not> have C<optional>
149set to true.
150
151=head2 C<check_parameters>
152
153  my %parameters = $service->check_parameters(name1=>$value1,name2=>$value2);
154  my %parameters = $service->check_parameters({name1=>$value1,name2=>$value2});
155
156If any L</parameters> are defined, this function validates its
157arguments against the parameters' definitions (using
158L<MooseX::Params::Validate>). It will die if the validation fails, or
159return the validated parameters (including default value) if it
160succeeds.
161
162=head2 C<get>
163
164I<Before> the C<get> method, arguments to C<get> are passed through
165L</check_parameters> and added to the L<<
166C<params>|Bread::Board::Service/params >> hashref. I<After> the C<get>
167method, those keys/values will be removed. In practice, this makes all
168parameters available to the actual C<get> method body.
169
170=head1 AUTHOR
171
172Stevan Little <stevan@iinteractive.com>
173
174=head1 BUGS
175
176Please report any bugs or feature requests on the bugtracker website
177https://github.com/stevan/BreadBoard/issues
178
179When submitting a bug or request, please include a test-file or a
180patch to an existing test-file that illustrates the bug or desired
181feature.
182
183=head1 COPYRIGHT AND LICENSE
184
185This software is copyright (c) 2019, 2017, 2016, 2015, 2014, 2013, 2011, 2009 by Infinity Interactive.
186
187This is free software; you can redistribute it and/or modify it under
188the same terms as the Perl 5 programming language system itself.
189
190=cut
191