File Coverage

File:C4/Message.pm
Coverage:14.3%

linestmtbrancondsubtimecode
1package C4::Message;
2
24
24
24
41768
156
824
use strict;
3
24
24
24
221
177
969
use warnings;
4
24
24
24
587
164
335
use C4::Context;
5
24
24
24
579
145
4022
use C4::Letters;
6
24
24
24
246
112
2049
use YAML::Syck;
7
24
24
24
182
146
36155
use Carp;
8
9 - 42
=head1 NAME

C4::Message - object for messages in the message_queue table

=head1 SYNOPSIS

How to add a new message to the queue:

  use C4::Message;
  use C4::Items;
  my $borrower = { borrowernumber => 1 };
  my $item     = C4::Items::GetItem(1);
  my $letter   = C4::Letters::getletter('circulation', 'CHECKOUT');
  C4::Letters::parseletter($letter, 'biblio', $item->{biblionumber});
  C4::Letters::parseletter($letter, 'biblioitems', $item->{biblionumber});
  C4::Message->enqueue($letter, $borrower->{borrowernumber}, 'email');

How to update a borrower's last checkout message:

  use C4::Message;
  my $borrower = { borrowernumber => 1 };
  my $message  = C4::Message->find_last_message($borrower, 'CHECKOUT', 'email');
  $message->append("you also checked out some other book....");
  $message->update;

=head1 DESCRIPTION

This module presents an OO interface to the message_queue.  Previously, 
you could only add messages to the message_queue via 
C<C4::Letters::EnqueueMessage()>.  With this module, you can also get 
previously inserted messages, manipulate them, and save them back to the 
database.

=cut
43
44
45our $AUTOLOAD;
46
47
48 - 54
=head2 Class Methods

=head3 C4::Message->new(\%attributes)

This method creates an in-memory version of a message object.

=cut
55
56# C4::Message->new(\%attributes) -- constructor
57sub new {
58
0
    my ($class, $opts) = @_;
59
0
    $opts ||= {};
60
0
    bless {%$opts} => $class;
61}
62
63
64 - 69
=head3 C4::Message->find($id)

This method searches the message_queue table for a row with the given
C<message_id> and it'll return a C4::Message object if it finds one.

=cut
70
71# C4::Message->find($id) -- find a message by its message_id
72sub find {
73
0
    my ($class, $id) = @_;
74
0
    my $dbh = C4::Context->dbh;
75
0
    my $msgs = $dbh->selectall_arrayref(
76        qq{SELECT * FROM message_queue WHERE message_id = ?},
77        { Slice => {} },
78        $id,
79    );
80
0
    if (@$msgs) {
81
0
        return $class->new($msgs->[0]);
82    } else {
83
0
        return undef;
84    }
85}
86
87 - 93
=head3 C4::Message->find_last_message($borrower, $letter_code, $transport)

This method is used to get the borrower's most recent, pending, check-in or
checkout message.  (This makes it possible to add more information to the
message before it gets sent out.)

=cut
94
95# C4::Message->find_last_message($borrower, $letter_code, $transport)
96# -- get the borrower's most recent pending checkin or checkout notification
97sub find_last_message {
98
0
    my ($class, $borrower, $letter_code, $transport) = @_;
99    # $type is the message_transport_type
100
0
    $transport ||= 'email';
101
0
    my $dbh = C4::Context->dbh;
102
0
    my $msgs = $dbh->selectall_arrayref(
103        qq{
104            SELECT *
105            FROM message_queue
106            WHERE status = 'pending'
107            AND borrowernumber = ?
108            AND letter_code = ?
109            AND message_transport_type = ?
110        },
111        { Slice => {} },
112        $borrower->{borrowernumber},
113        $letter_code,
114        $transport,
115    );
116
0
    if (@$msgs) {
117
0
        return $class->new($msgs->[0]);
118    } else {
119
0
        return undef;
120    }
121}
122
123
124 - 129
=head3 C4::Message->enqueue($letter, $borrower, $transport)

This is a front-end for C<C4::Letters::EnqueueLetter()> that adds metadata to
the message.

=cut
130
131# C4::Message->enqueue($letter, $borrower, $transport)
132sub enqueue {
133
0
    my ($class, $letter, $borrower, $transport) = @_;
134
0
    my $metadata = _metadata($letter);
135
0
    my $to_address = _to_address($borrower, $transport);
136
0
    $letter->{metadata} = Dump($metadata);
137    #carp "enqueuing... to $to_address";
138
0
    C4::Letters::EnqueueLetter({
139        letter => $letter,
140        borrowernumber => $borrower->{borrowernumber},
141        message_transport_type => $transport,
142        to_address => $to_address,
143    });
144}
145
146# based on message $transport, pick an appropriate address to send to
147sub _to_address {
148
0
    my ($borrower, $transport) = @_;
149
0
    my $address;
150
0
    if ($transport eq 'email') {
151
0
        $address = $borrower->{email}
152            || $borrower->{emailpro}
153            || $borrower->{B_email};
154    } elsif ($transport eq 'sms') {
155
0
        $address = $borrower->{smsalertnumber}
156            || $borrower->{phone}
157            || $borrower->{phonepro}
158            || $borrower->{B_phone};
159    } else {
160
0
        warn "'$transport' is an unknown message transport.";
161    }
162
0
    if (not defined $address) {
163
0
        warn "An appropriate $transport address "
164            . "for borrower $borrower->{userid} "
165            . "could not be found.";
166    }
167
0
    return $address;
168}
169
170# _metadata($letter) -- return the letter split into head/body/footer
171sub _metadata {
172
0
    my ($letter) = @_;
173
0
    if ($letter->{content} =~ /----/) {
174
0
        my ($header, $body, $footer) = split(/----\r?\n?/, $letter->{content});
175        return {
176
0
            header => $header,
177            body => [$body],
178            footer => $footer,
179        };
180    } else {
181        return {
182
0
            header => '',
183            body => [$letter->{content}],
184            footer => '',
185        };
186    }
187}
188
189 - 196
=head2 Instance Methods

=head3 $message->update()

This saves the $message object back to the database.  It needs to have
already been created via C<enqueue> for this to work.

=cut
197
198# $object->update -- save object to database
199sub update {
200
0
    my ($self) = @_;
201
0
    my $dbh = C4::Context->dbh;
202
0
    $dbh->do(
203        qq{
204            UPDATE message_queue
205            SET
206                borrowernumber = ?,
207                subject = ?,
208                content = ?,
209                metadata = ?,
210                letter_code = ?,
211                message_transport_type = ?,
212                status = ?,
213                time_queued = ?,
214                to_address = ?,
215                from_address = ?,
216                content_type = ?
217            WHERE message_id = ?
218        },
219        {},
220        $self->borrowernumber,
221        $self->subject,
222        $self->content,
223        $self->{metadata}, # we want the raw YAML here
224        $self->letter_code,
225        $self->message_transport_type,
226        $self->status,
227        $self->time_queued,
228        $self->to_address,
229        $self->from_address,
230        $self->content_type,
231        $self->message_id
232    );
233}
234
235 - 240
=head3 $message->metadata(\%new_metadata)

This method automatically serializes and deserializes the metadata
attribute.  (It is stored in YAML format.)

=cut
241
242# $object->metadata -- this is a YAML serialized column that contains a
243# structured representation of $object->content
244sub metadata {
245
0
    my ($self, $data) = @_;
246
0
    if ($data) {
247
0
        $data->{header} ||= '';
248
0
        $data->{body} ||= [];
249
0
        $data->{footer} ||= '';
250
0
        $self->{metadata} = Dump($data);
251
0
        $self->content($self->render_metadata);
252
0
        return $data;
253    } else {
254
0
        return Load($self->{metadata});
255    }
256}
257
258# turn $object->metadata into a string suitable for $object->content
259sub render_metadata {
260
0
    my ($self, $format) = @_;
261
0
0
    $format ||= sub { $_[0] || "" };
262
0
    my $metadata = $self->metadata;
263
0
    my $body = $metadata->{body};
264
0
0
    my $text = join('', map { $format->($_) } @$body);
265
0
    return $metadata->{header} . $text . $metadata->{footer};
266}
267
268 - 278
=head3 $message->append(\%letter)

If passed a hashref, this method will assume that the hashref is in the form
that C<C4::Letters::getletter()> returns.  It will append the body of the
letter to the message.

=head3 $message->append($string)

If passed a string, it'll append the string to the message.

=cut
279
280# $object->append($letter_or_item) -- add a new item to a message's content
281sub append {
282
0
    my ($self, $letter_or_item, $format) = @_;
283
0
    my $item;
284
0
    if (ref($letter_or_item)) {
285
0
        my $letter = $letter_or_item;
286
0
        my $metadata = _metadata($letter);
287
0
        $item = $metadata->{body}->[0];
288    } else {
289
0
        $item = $letter_or_item;
290    }
291
0
    if (not $self->metadata) {
292
0
        carp "Can't append to messages that don't have metadata.";
293
0
        return undef;
294    }
295
0
    my $metadata = $self->metadata;
296
0
0
    push @{$metadata->{body}}, $item;
297
0
    $self->metadata($metadata);
298
0
    my $new_content = $self->render_metadata($format);
299
0
    return $self->content($new_content);
300}
301
302 - 306
=head2 Attributes Accessors

=head3 $message->message_id

=cut
307
308 - 310
=head3 $message->borrowernumber

=cut
311
312 - 314
=head3 $message->subject

=cut
315
316 - 318
=head3 $message->content

=cut
319
320 - 322
=head3 $message->metadata

=cut
323
324 - 326
=head3 $message->letter_code

=cut
327
328 - 330
=head3 $message->message_transport_type

=cut
331
332 - 334
=head3 $message->status

=cut
335
336 - 338
=head3 $message->time_queued

=cut
339
340 - 342
=head3 $message->to_address

=cut
343
344 - 346
=head3 $message->from_address

=cut
347
348 - 350
=head3 $message->content_type

=cut
351
352# $object->$method -- treat keys as methods
353sub AUTOLOAD {
354
0
    my ($self, @args) = @_;
355
0
    my $attr = $AUTOLOAD;
356
0
    $attr =~ s/.*://;
357
0
    if (ref($self->{$attr}) eq 'CODE') {
358
0
        $self->{$attr}->($self, @args);
359    } else {
360
0
        if (@args) {
361
0
            $self->{$attr} = $args[0];
362        } else {
363
0
            $self->{$attr};
364        }
365    }
366}
367
368
0
sub DESTROY { }
369
3701;
371
372 - 380
=head1 SEE ALSO

L<C4::Circulation>, L<C4::Letters>, L<C4::Members::Messaging>

=head1 AUTHOR

John Beppu <john.beppu@liblime.com>

=cut