File Coverage

File:C4/Message.pm
Coverage:14.3%

linestmtbrancondsubtimecode
1package C4::Message;
2
14
14
14
475
71
879
use strict;
3
14
14
14
133
56
622
use warnings;
4
14
14
14
326
62
236
use C4::Context;
5
14
14
14
229
71
2346
use C4::Letters;
6
14
14
14
165
34
1115
use YAML::Syck;
7
14
14
14
119
64
20687
use Carp;
8
9 - 48
=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::GetPreparedLetter (
      module => 'circulation',
      letter_code => 'CHECKOUT',
      branchcode => $branch,
      tables => {
          'biblio', $item->{biblionumber},
          '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
49
50
51our $AUTOLOAD;
52
53
54 - 60
=head2 Class Methods

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

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

=cut
61
62# C4::Message->new(\%attributes) -- constructor
63sub new {
64
0
    my ($class, $opts) = @_;
65
0
    $opts ||= {};
66
0
    bless {%$opts} => $class;
67}
68
69
70 - 75
=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
76
77# C4::Message->find($id) -- find a message by its message_id
78sub find {
79
0
    my ($class, $id) = @_;
80
0
    my $dbh = C4::Context->dbh;
81
0
    my $msgs = $dbh->selectall_arrayref(
82        qq{SELECT * FROM message_queue WHERE message_id = ?},
83        { Slice => {} },
84        $id,
85    );
86
0
    if (@$msgs) {
87
0
        return $class->new($msgs->[0]);
88    } else {
89
0
        return undef;
90    }
91}
92
93 - 99
=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
100
101# C4::Message->find_last_message($borrower, $letter_code, $transport)
102# -- get the borrower's most recent pending checkin or checkout notification
103sub find_last_message {
104
0
    my ($class, $borrower, $letter_code, $transport) = @_;
105    # $type is the message_transport_type
106
0
    $transport ||= 'email';
107
0
    my $dbh = C4::Context->dbh;
108
0
    my $msgs = $dbh->selectall_arrayref(
109        qq{
110            SELECT *
111            FROM message_queue
112            WHERE status = 'pending'
113            AND borrowernumber = ?
114            AND letter_code = ?
115            AND message_transport_type = ?
116        },
117        { Slice => {} },
118        $borrower->{borrowernumber},
119        $letter_code,
120        $transport,
121    );
122
0
    if (@$msgs) {
123
0
        return $class->new($msgs->[0]);
124    } else {
125
0
        return undef;
126    }
127}
128
129
130 - 135
=head3 C4::Message->enqueue($letter, $borrower, $transport)

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

=cut
136
137# C4::Message->enqueue($letter, $borrower, $transport)
138sub enqueue {
139
0
    my ($class, $letter, $borrower, $transport) = @_;
140
0
    my $metadata = _metadata($letter);
141
0
    my $to_address = _to_address($borrower, $transport);
142
0
    $letter->{metadata} = Dump($metadata);
143    #carp "enqueuing... to $to_address";
144
0
    C4::Letters::EnqueueLetter({
145        letter => $letter,
146        borrowernumber => $borrower->{borrowernumber},
147        message_transport_type => $transport,
148        to_address => $to_address,
149    });
150}
151
152# based on message $transport, pick an appropriate address to send to
153sub _to_address {
154
0
    my ($borrower, $transport) = @_;
155
0
    my $address;
156
0
    if ($transport eq 'email') {
157
0
        $address = $borrower->{email}
158            || $borrower->{emailpro}
159            || $borrower->{B_email};
160    } elsif ($transport eq 'sms') {
161
0
        $address = $borrower->{smsalertnumber}
162            || $borrower->{phone}
163            || $borrower->{phonepro}
164            || $borrower->{B_phone};
165    } else {
166
0
        warn "'$transport' is an unknown message transport.";
167    }
168
0
    if (not defined $address) {
169
0
        warn "An appropriate $transport address "
170            . "for borrower $borrower->{userid} "
171            . "could not be found.";
172    }
173
0
    return $address;
174}
175
176# _metadata($letter) -- return the letter split into head/body/footer
177sub _metadata {
178
0
    my ($letter) = @_;
179
0
    if ($letter->{content} =~ /----/) {
180
0
        my ($header, $body, $footer) = split(/----\r?\n?/, $letter->{content});
181        return {
182
0
            header => $header,
183            body => [$body],
184            footer => $footer,
185        };
186    } else {
187        return {
188
0
            header => '',
189            body => [$letter->{content}],
190            footer => '',
191        };
192    }
193}
194
195 - 202
=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
203
204# $object->update -- save object to database
205sub update {
206
0
    my ($self) = @_;
207
0
    my $dbh = C4::Context->dbh;
208
0
    $dbh->do(
209        qq{
210            UPDATE message_queue
211            SET
212                borrowernumber = ?,
213                subject = ?,
214                content = ?,
215                metadata = ?,
216                letter_code = ?,
217                message_transport_type = ?,
218                status = ?,
219                time_queued = ?,
220                to_address = ?,
221                from_address = ?,
222                content_type = ?
223            WHERE message_id = ?
224        },
225        {},
226        $self->borrowernumber,
227        $self->subject,
228        $self->content,
229        $self->{metadata}, # we want the raw YAML here
230        $self->letter_code,
231        $self->message_transport_type,
232        $self->status,
233        $self->time_queued,
234        $self->to_address,
235        $self->from_address,
236        $self->content_type,
237        $self->message_id
238    );
239}
240
241 - 246
=head3 $message->metadata(\%new_metadata)

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

=cut
247
248# $object->metadata -- this is a YAML serialized column that contains a
249# structured representation of $object->content
250sub metadata {
251
0
    my ($self, $data) = @_;
252
0
    if ($data) {
253
0
        $data->{header} ||= '';
254
0
        $data->{body} ||= [];
255
0
        $data->{footer} ||= '';
256
0
        $self->{metadata} = Dump($data);
257
0
        $self->content($self->render_metadata);
258
0
        return $data;
259    } else {
260
0
        return Load($self->{metadata});
261    }
262}
263
264# turn $object->metadata into a string suitable for $object->content
265sub render_metadata {
266
0
    my ($self, $format) = @_;
267
0
0
    $format ||= sub { $_[0] || "" };
268
0
    my $metadata = $self->metadata;
269
0
    my $body = $metadata->{body};
270
0
0
    my $text = join('', map { $format->($_) } @$body);
271
0
    return $metadata->{header} . $text . $metadata->{footer};
272}
273
274 - 284
=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
285
286# $object->append($letter_or_item) -- add a new item to a message's content
287sub append {
288
0
    my ($self, $letter_or_item, $format) = @_;
289
0
    my $item;
290
0
    if (ref($letter_or_item)) {
291
0
        my $letter = $letter_or_item;
292
0
        my $metadata = _metadata($letter);
293
0
        $item = $metadata->{body}->[0];
294    } else {
295
0
        $item = $letter_or_item;
296    }
297
0
    if (not $self->metadata) {
298
0
        carp "Can't append to messages that don't have metadata.";
299
0
        return undef;
300    }
301
0
    my $metadata = $self->metadata;
302
0
0
    push @{$metadata->{body}}, $item;
303
0
    $self->metadata($metadata);
304
0
    my $new_content = $self->render_metadata($format);
305
0
    return $self->content($new_content);
306}
307
308 - 312
=head2 Attributes Accessors

=head3 $message->message_id

=cut
313
314 - 316
=head3 $message->borrowernumber

=cut
317
318 - 320
=head3 $message->subject

=cut
321
322 - 324
=head3 $message->content

=cut
325
326 - 328
=head3 $message->metadata

=cut
329
330 - 332
=head3 $message->letter_code

=cut
333
334 - 336
=head3 $message->message_transport_type

=cut
337
338 - 340
=head3 $message->status

=cut
341
342 - 344
=head3 $message->time_queued

=cut
345
346 - 348
=head3 $message->to_address

=cut
349
350 - 352
=head3 $message->from_address

=cut
353
354 - 356
=head3 $message->content_type

=cut
357
358# $object->$method -- treat keys as methods
359sub AUTOLOAD {
360
0
    my ($self, @args) = @_;
361
0
    my $attr = $AUTOLOAD;
362
0
    $attr =~ s/.*://;
363
0
    if (ref($self->{$attr}) eq 'CODE') {
364
0
        $self->{$attr}->($self, @args);
365    } else {
366
0
        if (@args) {
367
0
            $self->{$attr} = $args[0];
368        } else {
369
0
            $self->{$attr};
370        }
371    }
372}
373
374
0
sub DESTROY { }
375
3761;
377
378 - 386
=head1 SEE ALSO

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

=head1 AUTHOR

John Beppu <john.beppu@liblime.com>

=cut