package C4::Message; use strict; use warnings; use C4::Context; use C4::Letters; use YAML::Syck; use Carp; =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. With this module, you can also get previously inserted messages, manipulate them, and save them back to the database. =cut our $AUTOLOAD; =head2 Class Methods =head3 C4::Message->new(\%attributes) This method creates an in-memory version of a message object. =cut # C4::Message->new(\%attributes) -- constructor sub new { my ($class, $opts) = @_; $opts ||= {}; bless {%$opts} => $class; } =head3 C4::Message->find($id) This method searches the message_queue table for a row with the given C and it'll return a C4::Message object if it finds one. =cut # C4::Message->find($id) -- find a message by its message_id sub find { my ($class, $id) = @_; my $dbh = C4::Context->dbh; my $msgs = $dbh->selectall_arrayref( qq{SELECT * FROM message_queue WHERE message_id = ?}, { Slice => {} }, $id, ); if (@$msgs) { return $class->new($msgs->[0]); } else { return undef; } } =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 # C4::Message->find_last_message($borrower, $letter_code, $transport) # -- get the borrower's most recent pending checkin or checkout notification sub find_last_message { my ($class, $borrower, $letter_code, $transport) = @_; # $type is the message_transport_type $transport ||= 'email'; my $dbh = C4::Context->dbh; my $msgs = $dbh->selectall_arrayref( qq{ SELECT * FROM message_queue WHERE status = 'pending' AND borrowernumber = ? AND letter_code = ? AND message_transport_type = ? }, { Slice => {} }, $borrower->{borrowernumber}, $letter_code, $transport, ); if (@$msgs) { return $class->new($msgs->[0]); } else { return undef; } } =head3 C4::Message->enqueue($letter, $borrowernumber, $transport) This is a front-end for C that adds metadata to the message. =cut # C4::Message->enqueue($letter, $borrowernumber, $transport) sub enqueue { my ($class, $letter, $borrowernumber, $transport) = @_; my $metadata = _make_metadata($letter); $letter->{metadata} = Dump($metadata); carp 'enqueuing...'; C4::Letters::EnqueueLetter({ letter => $letter, borrowernumber => $borrowernumber, message_transport_type => $transport, }); } # _make_metadata($letter) -- return the letter split into head/body/footer sub _make_metadata { my ($letter) = @_; if ($letter->{content} =~ /----/) { my ($header, $body, $footer) = split(/----\r?\n?/, $letter->{content}); return { header => $header, body => [$body], footer => $footer, }; } else { return { header => '', body => [$letter->{content}], footer => '', }; } } =head2 Instance Methods =head3 $message->update() This saves the $message object back to the database. It needs to have already been created via C for this to work. =cut # $object->update -- save object to database sub update { my ($self) = @_; my $dbh = C4::Context->dbh; $dbh->do( qq{ UPDATE message_queue SET borrowernumber = ?, subject = ?, content = ?, metadata = ?, letter_code = ?, message_transport_type = ?, status = ?, time_queued = ?, to_address = ?, from_address = ?, content_type = ? WHERE message_id = ? }, {}, $self->borrowernumber, $self->subject, $self->content, $self->{metadata}, # we want the raw YAML here $self->letter_code, $self->message_transport_type, $self->status, $self->time_queued, $self->to_address, $self->from_address, $self->content_type, $self->message_id ); } =head3 $message->metadata(\%new_metadata) This method automatically serializes and deserializes the metadata attribute. (It is stored in YAML format.) =cut # $object->metadata -- this is a YAML serialized column that contains a # structured representation of $object->content sub metadata { my ($self, $data) = @_; if ($data) { $data->{header} ||= ''; $data->{body} ||= []; $data->{footer} ||= ''; $self->{metadata} = Dump($data); $self->content($self->render_metadata); return $data; } else { return Load($self->{metadata}); } } # turn $object->metadata into a string suitable for $object->content sub render_metadata { my ($self, $format) = @_; $format ||= sub { $_[0] || "" }; my $metadata = $self->metadata; my $body = $metadata->{body}; my $text = join('', map { $format->($_) } @$body); return $metadata->{header} . $text . $metadata->{footer}; } =head3 $message->append(\%letter) If passed a hashref, this method will assume that the hashref is in the form that C 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 # $object->append($letter_or_item) -- add a new item to a message's content sub append { my ($self, $letter_or_item, $format) = @_; my $item; if (ref($letter_or_item)) { my $letter = $letter_or_item; my $metadata = _make_metadata($letter); $item = $metadata->{body}->[0]; } else { $item = $letter_or_item; } if (not $self->metadata) { carp "Can't append to messages that don't have metadata."; return undef; } my $metadata = $self->metadata; push @{$metadata->{body}}, $item; $self->metadata($metadata); my $new_content = $self->render_metadata($format); return $self->content($new_content); } =head2 Attributes Accessors =head3 $message->message_id =head3 $message->borrowernumber =head3 $message->subject =head3 $message->content =head3 $message->metadata =head3 $message->letter_code =head3 $message->message_transport_type =head3 $message->status =head3 $message->time_queued =head3 $message->to_address =head3 $message->from_address =head3 $message->content_type =cut # $object->$method -- treat keys as methods sub AUTOLOAD { my ($self, @args) = @_; my $attr = $AUTOLOAD; $attr =~ s/.*://; if (ref($self->{$attr}) eq 'CODE') { $self->{$attr}->($self, @args); } else { if (@args) { $self->{$attr} = $args[0]; } else { $self->{$attr}; } } } sub DESTROY { } 1; =head1 SEE ALSO L, L, L =head1 AUTHOR John Beppu =cut # Local Variables: *** # mode: cperl *** # indent-tabs-mode: nil *** # cperl-close-paren-offset: -4 *** # cperl-continued-statement-offset: 4 *** # cperl-indent-level: 4 *** # cperl-indent-parens-as-block: t *** # cperl-tab-always-indent: nil *** # End: *** # vim:tabstop=8 softtabstop=4 shiftwidth=4 shiftround expandtab