File Coverage

blib/lib/CMS/Drupal/Modules/MembershipEntity.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package CMS::Drupal::Modules::MembershipEntity;
2             $CMS::Drupal::Modules::MembershipEntity::VERSION = '0.092';
3              
4             # ABSTRACT: Perl interface to Drupal MembershipEntity entities
5              
6 1     1   31844 use Moo;
  1         11993  
  1         6  
7 1     1   1717 use Types::Standard qw/ :all /;
  1         54400  
  1         22  
8 1     1   29872 use Time::Local;
  1         1571  
  1         64  
9 1     1   459 use CMS::Drupal::Modules::MembershipEntity::Membership;
  0            
  0            
10             use CMS::Drupal::Modules::MembershipEntity::Term;
11             use Data::Dumper;
12             use Carp qw/ carp croak confess /;
13             use 5.010;
14              
15             has dbh => ( is => 'ro', isa => InstanceOf['DBI::db'], required => 1 );
16             has prefix => ( is => 'ro', isa => Maybe[StrMatch[ qr/ \w+_ /x ]] );
17              
18             sub fetch_memberships {
19              
20             my $self = shift;
21             my $prefix = $self->{'prefix'} || '';
22              
23             ## We accept an arrayref of mids as an optional parameter
24              
25             my $mids = shift;
26             my $WHERE = ' ';
27            
28             if ( $mids ) {
29             if ( scalar @{ $mids } < 1 ) {
30             carp "Empty arrayref passed to fetch_memberships() ... returning all Memberships";
31             }
32              
33             for (@$mids) {
34             # Let's be real strict about what we try to pass in to the DBMS
35             confess "FATAL: Invalid 'mid' (must be all ASCII digits)."
36             unless /^\d+$/a;
37            
38             $WHERE = 'WHERE ';
39             $WHERE .= "mid = '$_' OR " for @$mids;
40             $WHERE =~ s/ OR $//;
41             }
42             }
43            
44             my $temp;
45             my $memberships;
46              
47             ## Get the Membership info
48             my $sql = qq|
49             SELECT mid, member_id, type, uid, status, created, changed
50             FROM ${prefix}membership_entity
51             $WHERE
52             |;
53            
54             my $sth = $self->{'dbh'}->prepare( $sql );
55             $sth->execute;
56            
57             my $results = $sth->fetchall_hashref('mid');
58             foreach my $mid (keys( %$results )) {
59             $temp->{ $mid } = $results->{ $mid };
60             }
61            
62             ## Get the Membership Term info
63             # Use the $WHERE clause from the optional mids parameter
64             my $sql2 = qq|
65             SELECT id as tid, mid, status, term, modifiers, start, end
66             FROM ${prefix}membership_entity_term
67             $WHERE
68             ORDER BY start
69             |;
70            
71             my $sth2 = $self->{'dbh'}->prepare( $sql2 );
72             $sth2->execute;
73              
74             my %term_count; # used to track array position of Terms
75              
76             while( my $row = $sth2->fetchrow_hashref ) {
77             ## Shouldn't be, but is, possible to have a Term with no start or end
78             if ( not defined $row->{'start'} or not defined $row->{'end'} ) {
79             carp "MISSING DATE: tid< $row->{'tid'} > " .
80             "(uid< $temp->{ $row->{'mid'} }->{'uid'} >) has no start " .
81             "or end date defined. Skipping ...";
82             next;
83             }
84              
85             ## convert the start and end to unixtime
86             for (qw/ start end /) {
87             my @datetime = reverse (split /[-| |:]/, $row->{ $_ });
88             $datetime[4]--;
89             $row->{ $_ } = timelocal( @datetime );
90             }
91              
92             ## Track which of the Membership's Terms this is
93             $term_count{ $row->{'mid'} }++;
94             $row->{'array_position'} = $term_count{ $row->{'mid'} };
95            
96             ## Instantiate a MembershipEntity::Term object for each
97             ## Term now that we have the data
98             my $term = CMS::Drupal::Modules::MembershipEntity::Term->new( $row );
99             $temp->{ $row->{'mid'} }->{ 'terms' }->{ $row->{'tid'} } = $term;
100             }
101              
102             ## Instantiate a MembershipEntity::Membership object for each
103             ## Membership now that we have the data
104             foreach my $mid( keys( %$temp )) {
105            
106             ## Shouldn't be, but is, possible to have a Membership with no Term
107             if (not defined $temp->{ $mid }->{'terms'}) {
108             carp "MISSING TERM: mid< $mid > (uid< $temp->{ $mid }->{'uid'} >) " .
109             "has no Membership Terms. Skipping ...";
110             next;
111             }
112            
113             $memberships->{ $mid } =
114             CMS::Drupal::Modules::MembershipEntity::Membership->new( $temp->{ $mid } );
115             }
116            
117             return $memberships;
118             }
119              
120             1; ## return true to end package CMS::Drupal::Modules::MembershipEntity
121              
122             =pod
123              
124             =head1 NAME
125              
126             CMS::Drupal::Modules::MembershipEntity
127              
128             =head1 VERSION
129              
130             version 0.092
131              
132             =head1 SYNOPSIS
133              
134             use CMS::Drupal::Modules::MembershipEntity;
135              
136             my $ME = CMS::Drupal::Modules::MembershipEntity->new( dbh => $dbh );
137              
138             my $hashref = $ME->fetch_memberships;
139             # or:
140             my $hashref = $ME->fetch_memberships([ 123, 456, 789 ]);
141             # or:
142             my $hashref = $ME->fetch_memberships([ 123 ]);
143             # or:
144             my $hashref = $ME->fetch_memberships( \@list );
145            
146             foreach my $mid ( sort keys %{$hashref} ) {
147             my $mem = $hashref->{ $mid };
148            
149             print $mem->{'type'};
150             &send_newsletter( $mem->{'uid'} ) if $mem->active;
151            
152             # etc ...
153             }
154              
155             =head1 USAGE
156              
157             This package returns a hashref containing one element for each Membership that
158             was requested. The hashref is indexed by B and the element is a Membership
159             object, which contains at least one Term object, so you have access to all the
160             methods you can use on your Membership.
161              
162             For this reason the methods actually provided by the submodules are documented
163             here.
164              
165             =head2 METHODS
166              
167             =head2 fetch_memberships
168              
169             This method returns a hashref containing Membership objects indexed by B.
170              
171             When called with no arguments, the hashref contains all Memberships in the
172             Drupal database, which might be too much for your memory if you have lots
173             of them.
174              
175             When called with an arrayref containing Bs, the hashref will contain an
176             object for each mid in the arrayref.
177              
178             # Fetch a single Membership
179             my $hashref = $ME->fetch_memberships([ 1234 ]);
180              
181             # Fetch a set of Memberships
182             my $hashref = $ME->fetch_memberships([ 1234, 5678 ]);
183              
184             # Fetch a set of Memberships using a list you prepared elsewhere
185             my $hashref = $ME->fetch_memberships( $array_ref );
186              
187             # Fetch all your Memberships
188             my $hashref = $ME->fetch_memberships;
189              
190             =head2 Memberships
191              
192             This module uses CMS::Drupal::Modules::MembershipEntity::Membership so you
193             don't have to. The methods described below are actually in the latter
194             module.
195              
196             my $hashref = $ME->fetch_memberships([ 1234 ]);
197             my $mem = $hashref->{'1234'};
198              
199             =head3 Attributes
200              
201             You can directly access all the Membership's attributes as follows:
202              
203             $mem->{ attr_name }
204              
205             Where attr_name is one of:
206              
207             mid
208             member_id
209             type
210             uid
211             status
212             created
213             changed
214              
215             There is also another attribute `terms`, which contains an hashref of Term
216             objects, indexed by B. Each Term can be accessed by the methods described
217             in the Membership Terms section below.
218              
219             =head3 is_active
220              
221             Returns true if the Membership status is active, else returns false.
222              
223             say "User $mem->{'uid'} is in good standing" if $mem->is_active;
224              
225             =head3 has_renewal
226              
227             Returns true if the Membership has at least one Term for which
228             is_future returns true.
229              
230             say "User $mem->{'uid'} has already renewed" if $mem->has_renewal;
231              
232             =head2 Membership Terms
233              
234             This module uses CMS::Drupal::Modules::MembershipEntity::Term so you
235             don't have to. The methods described below are actually in the latter
236             module.
237              
238             while ( my ($tid, $term) = each %{$mem->{'terms'}} ) {
239             # do something ...
240             }
241              
242             =head3 Attributes
243              
244             You can directly access all the Term's attributes as follows:
245              
246             $term->{ attr_name }
247              
248             Where attr_name is one of:
249              
250             tid
251             mid
252             status
253             term
254             modifiers
255             start
256             end
257              
258             There is also another attribute, `array_position`, which is used to determine if
259             the Term is a renewal, etc.
260              
261             =head3 is_active
262              
263             Returns true if the Term status is active, else returns false.
264             (Note that 'active' does not necessarily mean 'current', see below.)
265              
266             say "$term->{'tid'} is active" if $term->is_active;
267              
268             =head3 is_current
269              
270             Returns true if the Term is current, meaning that the datetime now
271             falls between the start and end of the Term.
272             (Note that the Term may be 'current' but not 'active', eg 'pending'.)
273              
274             say "This is a live one" if $term->is_current;
275              
276             =head3 is_future
277              
278             Returns true if the `start` of the Term is in the future compared to now.
279              
280             say "$mem->{'uid'} has a prepaid renewal" if $term->is_future;
281              
282             =head3 was_renewal
283              
284             Returns true if the Term was a renewal when it was created (as determined
285             simply by the fact that there was an earlier one).
286              
287             say "$mem->{'uid'} is a repeat customer" if $term->was_renewal;
288              
289              
290             =head1 SEE ALSO
291              
292             L
293              
294             L
295              
296             L
297              
298             =cut