File Coverage

blib/lib/Interchange6/Schema/Base/Attribute.pm
Criterion Covered Total %
statement 87 87 100.0
branch 24 24 100.0
condition 3 3 100.0
subroutine 11 11 100.0
pod 8 8 100.0
total 133 133 100.0


line stmt bran cond sub pod time code
1 2     2   20 use utf8;
  2         5  
  2         12  
2             package Interchange6::Schema::Base::Attribute;
3              
4             =head1 NAME
5              
6             Interchange6::Schema::Base::Attribute
7              
8             =cut
9              
10 2     2   84 use strict;
  2         4  
  2         40  
11 2     2   11 use warnings;
  2         4  
  2         2264  
12              
13             =head1 DESCRIPTION
14              
15             The Attribute base class is consumed by classes with attribute
16             relationships like L<Interchange6::Schema::Result::User>,
17             L<Interchange6::Schema::Result::Navigation>
18             and L<Interchange6::Schema::Result::Product>.
19              
20             =over 4
21              
22             =item B<Assumptions>
23              
24             This module assumes that your using standardized class naming.
25              
26             example: User in this example is the $base class so UserAttribute,
27             UserAttributeValue class naming would be used. These would
28             also use user_attributes_id and user_attributes_values_id as primary
29             keys. In general follow the example classes listed in description.
30              
31             =back
32              
33             =cut
34              
35             =head1 SYNOPSIS
36              
37             $navigation_object->add_attribute('meta_title','My very seductive title here!');
38              
39             =head1 METHODS
40              
41             =head2 add_attribute
42              
43             Add attribute.
44              
45             $base->add_attribute('hair_color', 'blond');
46              
47             Where 'hair_color' is Attribute and 'blond' is AttributeValue
48              
49             =cut
50              
51             sub add_attribute {
52 85     85 1 464892 my ($self, $attr, $attr_value) = @_;
53 85         429 my $base = $self->result_source->source_name;
54              
55             # find or create attributes
56 85         1039 my ($attribute, $attribute_value) = $self->find_or_create_attribute($attr, $attr_value);
57              
58             # create base_attribute object
59 85         680 my $base_attribute = $self->find_or_create_related(lc($base) . '_attributes',
60             {attributes_id => $attribute->id});
61             # create base_attribute_value
62 85         846259 $base_attribute->create_related(lc($base) . '_attribute_values',
63             {attribute_values_id => $attribute_value->id});
64              
65 85         344315 return $self;
66             }
67              
68             =head2 update_attribute_value
69              
70             Update base attribute value
71              
72             $base->update_attribute('hair_color', 'brown');
73              
74             =cut
75              
76             sub update_attribute_value {
77 2     2 1 2053 my ($self, $attr, $attr_value) = @_;
78 2         15 my $base = $self->result_source->source_name;
79              
80 2         36 my ($attribute, $attribute_value) = $self->find_or_create_attribute($attr, $attr_value);
81              
82 2         52 my (undef, $base_attribute_value) = $self->find_base_attribute_value($attribute, $base);
83              
84 2         48 $base_attribute_value->update({attribute_values_id => $attribute_value->id});
85              
86 2         4758 return $self;
87             }
88              
89             =head2 delete_attribute
90              
91             Delete $base attribute
92              
93             $base->delete_attribute('hair_color', 'purple');
94              
95             =cut
96              
97             sub delete_attribute {
98 2     2 1 1625 my ($self, $attr, $attr_value) = @_;
99 2         13 my $base = $self->result_source->source_name;
100              
101 2         29 my ($attribute) = $self->find_or_create_attribute($attr, $attr_value);
102              
103 2         14 my ($base_attribute, $base_attribute_value) = $self->find_base_attribute_value($attribute, $base);
104              
105             #delete
106 2         93 $base_attribute_value->delete;
107 2         3359 $base_attribute->delete;
108              
109 2         3256 return $self;
110             }
111              
112             =head2 search_attributes
113              
114             Returns attributes resultset for a $base object
115              
116             $rs = $base->search_attributes;
117              
118             You can pass conditions and attributes to the search like for
119             any L<DBIx::Class::ResultSet>, e.g.:
120              
121             $rs = $base->search_attributes(
122             undef, { order_by => 'priority desc' });
123              
124             =cut
125              
126             sub search_attributes {
127 5     5 1 26374 my ($self, $condition, $search_atts) = @_;
128              
129 5         22 my $base = $self->result_source->source_name;
130              
131 5         61 my $base_attributes = $self->search_related(lc($base) . '_attributes');
132              
133 5         3619 my $attributes = $base_attributes->search_related('attribute',
134             $condition, $search_atts);
135              
136 5         11146 return $attributes;
137             }
138              
139             =head2 find_attribute_value
140              
141             Finds the attribute value for the current object or a defined object value.
142             If $object is passed the entire attribute_value object will be returned. $args can
143             accept both scalar and hash inputs.
144              
145             $base->find_attribute_value({name => $attr_name, priority => $attr_priority}, {object => 1});
146              
147             =cut
148              
149             sub find_attribute_value {
150 12     12 1 10440 my ($self, $args, $object) = @_;
151 12         52 my $base = $self->result_source->source_name;
152 12         123 my $lc_base = lc($base);
153              
154             # attribute must be set
155 12 100       50 unless ($args) {
156 1         12 die "find_attribute_value input requires at least a valid attribute value";
157             };
158              
159 11 100       65 my %attr = ref($args) eq 'HASH' ? %{$args} : (name => $args);
  1         11  
160              
161 11         36 my $attribute = $self->result_source->schema->resultset('Attribute')->find( \%attr );
162              
163 11 100       67005 unless ($attribute) {
164 1         67 return undef;
165             }
166              
167             # find records
168 10         258 my $base_attribute = $self->find_related($lc_base . '_attributes',
169             {attributes_id => $attribute->id});
170              
171 10 100       63910 unless ($base_attribute) {
172 1         34 return undef;
173             }
174              
175 9         379 my $base_attribute_value = $base_attribute->find_related($lc_base .'_attribute_values',
176             {$lc_base . '_attributes_id' => $base_attribute->id});
177 9 100       53044 unless ($base_attribute_value) {
178 1         27 return undef;
179             }
180              
181 8         251 my $attribute_value = $base_attribute_value->find_related('attribute_value',
182             {lc($base) .'_attribute_values_id' => $base_attribute_value->id});
183 8 100       32154 if ($object) {
184 1         30 return $attribute_value;
185             }
186             else {
187 7         389 return $attribute_value->value;
188             }
189             };
190              
191             =head2 search_attribute_values
192              
193             =over 4
194              
195             =item Arguments: L<$cond|DBIx::Class::SQLMaker> | undef, L<\%attrs|DBIx::Class::ResultSet/ATTRIBUTES> | undef, L<\%av_attrs|DBIx::Class::ResultSet/ATTRIBUTES>
196              
197             Where $cond and %attrs are passed to the Attribute search and %av_attrs is passed to the AttributeValue search.
198              
199             =item Return Value: Array (or arrayref in scalar context) of attributes and values for for the $base object input.
200              
201             =back
202              
203             my $product = $schema->resultset('Product')->find({ sku = '123' });
204             my $av = $product->search_attribute_values(
205             undef, { order_by => 'priority' }, { order_by => 'priority' });
206              
207             =cut
208              
209             sub search_attribute_values {
210 2     2 1 58639 my ($self, $condition, $search_atts, $av_search_atts) = @_;
211 2         12 my $base = $self->result_source->source_name;
212 2         21 my (%base_data, %attr_values, @data);
213              
214 2         13 my $base_attributes = $self->search_related(lc($base) . '_attributes');
215              
216 2         547 my $attributes_rs = $base_attributes->search_related('attribute',
217             $condition, $search_atts);
218              
219 2         4181 while (my $attribute = $attributes_rs->next) {
220 4         14355 my @values;
221 4         18 my $attribute_value_rs = $attribute->search_related('attribute_values',
222             undef, $av_search_atts);
223 4         6174 while (my $attribute_value = $attribute_value_rs->next) {
224              
225             # get key value pairs
226 6         10227 my %attr_values = $attribute_value->get_columns;
227 6         110 push( @values, { %attr_values });
228             }
229 4         433 my %base_data = $attribute->get_columns;
230              
231             # populate values
232 4         84 $base_data{attribute_values} = \@values;
233 4         30 push( @data, { %base_data });
234             }
235 2 100       427 return wantarray ? @data : \@data;
236             };
237              
238             =head2 find_or_create_attribute
239              
240             Find or create attribute and attribute_value.
241              
242             =cut
243              
244             sub find_or_create_attribute {
245 93     93 1 3505 my ( $self, $attr, $value ) = @_;
246              
247 93 100 100     720 unless ( defined($attr) && defined($value) ) {
248 3         36 die "Both attribute and attribute value are required for find_or_create_attribute";
249             }
250              
251             # check if $attr is a HASH if not set as name
252 90 100       419 my %attr = ref($attr) eq 'HASH' ? %{$attr} : (name => $attr);
  52         281  
253              
254             # check if $value is a HASH if not set as value
255 90 100       471 my %attr_value = ref($value) eq 'HASH' ? %{$value} : (value => $value);
  3         12  
256              
257 90         323 my $attribute = $self->result_source->schema->resultset('Attribute')->find_or_create( %attr );
258              
259             # create attribute_values
260 90         490587 my $attribute_value = $attribute->find_or_create_related('attribute_values', \%attr_value );
261              
262 90         590981 return ($attribute, $attribute_value);
263             };
264              
265             =head2 find_base_attribute_value
266              
267             From a $base->attribute input $base_attribute, $base_attribute_value is returned.
268              
269             =cut
270              
271             sub find_base_attribute_value {
272 7     7 1 1972 my ($self, $attribute, $base) = @_;
273              
274 7 100       34 unless($base) {
275 2         20 die "Missing base name for find_base_attribute_value";
276             }
277              
278 5 100       24 unless($attribute) {
279 1         10 die "Missing attribute object for find_base_attribute_value";
280             }
281              
282 4         13 my $lc_base = lc($base);
283              
284 4         22 my $base_attribute = $self->find_related($lc_base . '_attributes',
285             {attributes_id => $attribute->id});
286              
287 4         22164 my $base_attribute_value = $base_attribute->find_related($lc_base . '_attribute_values',
288             {$lc_base . '_attributes_id' => $base_attribute->id});
289              
290 4         23302 return ($base_attribute, $base_attribute_value);
291             }
292              
293              
294             1;