コード例 #1
0
 /**
  * Publish objects in the 'query' whose publication state matches 'state'.
  * Notifications are sent according to user preferences by default.
  * @param HISTORY_ITEM_QUERY $query
  */
 public function publish_history_items($query)
 {
     $this->app->display_options->overridden_max_title_size = 100;
     /* Build an indexed list of all history items in the query. */
     $query->restrict("act.publication_state = '" . History_item_needs_send . "'");
     $query->set_order('act.access_id ASC, act.object_type ASC, act.time_created ASC');
     $query_history_items = $query->indexed_objects();
     $num_history_items = sizeof($query_history_items);
     $this->record("[{$num_history_items}] history items found matching given query.");
     /* Retrieve a list of all subscribers that have pending history items. */
     $sub_query = new SUBSCRIBER_QUERY($this->app);
     $sub_query->restrict("queued_history_item_ids <> ''");
     $sub_query->restrict('time_messages_sent + INTERVAL min_hours_to_wait HOUR <= NOW()');
     $subscribers = $sub_query->objects();
     $this->record("[" . sizeof($subscribers) . "] subscribers found with pending history items.");
     /* For each subscriber that is now ready to receive messages, search the list of
        queued history items, building a global list of history items that are not already in the list
        generated by the query above. */
     $queued_history_item_ids = array();
     foreach ($subscribers as $subscriber) {
         if ($subscriber->ready_for_messages()) {
             if ($subscriber->queued_history_item_ids) {
                 $history_item_ids = explode(',', $subscriber->queued_history_item_ids);
                 foreach ($history_item_ids as $history_item_id) {
                     if (!isset($query_history_items[$history_item_id]) && !isset($queued_history_item_ids[$history_item_id])) {
                         $queued_history_item_ids[$history_item_id] = $history_item_id;
                     }
                 }
             }
         }
     }
     /* If there were any queued history items ready to send to subscribers, get them and add
        them to the list. Otherwise, use the list from the given query. */
     if (sizeof($queued_history_item_ids)) {
         $this->record("[" . sizeof($queued_history_item_ids) . "] unique pending history items found in subscribers.");
         $queued_history_item_ids_string = implode(',', $queued_history_item_ids);
         $queued_history_item_query = $this->login->all_history_item_query();
         $queued_history_items = $queued_history_item_query->indexed_objects_at_ids($queued_history_item_ids_string);
         if (sizeof($query_history_items)) {
             $history_items = $query_history_items + $queued_history_items;
             /* Used to use: ksort ($history_items, SORT_NUMERIC);, but we actually
                want a sort by folder id, object type, object id. ... */
         } else {
             $history_items = $queued_history_items;
         }
     } else {
         $history_items = $query_history_items;
     }
     $num_history_items = sizeof($history_items);
     /* The list of history items now contains all the history items that were passed in with the query
        (this is the list of history items the application is publishing now) and all of the history items
        that are now publishable for those subscribers that are using queued delivery. */
     if ($num_history_items) {
         /* Build a three-dimensional array of history items, grouping them by [type][object][history_item]. */
         foreach ($history_items as $history_item_id => $history_item) {
             $sorted_history_items[$history_item->object_type][$history_item->object_id][] = $history_item;
         }
         /* Build a two-dimensional array of objects, grouping them by [type][object]. */
         foreach ($sorted_history_items as $object_type => $objects_and_history_items) {
             if ($object_type) {
                 $objects[$object_type] = array();
                 $query = $this->_object_query_for($object_type);
                 /* If this is not set, an error is raised, but it is possible to
                    ignore errors when publishing, so make sure not to attempt to
                    use the query. */
                 if (isset($query)) {
                     $object_ids = array_keys($objects_and_history_items);
                     $query->restrict_by_op($query->alias . '.id', $object_ids, Operator_in);
                     $objects[$object_type] = $query->indexed_objects();
                     /* If this is the folder query, make sure to remove the restriction so that ensuing queries
                        using the folder query don't inherit it. */
                     $query->clear_restrictions();
                 }
             } else {
                 $this->record('Empty object type was ignored (bad data).', Msg_type_warning);
             }
         }
         /* Build a list of subscribers, with structure [email].objects[folder][type][id].history_items */
         $subscriber_records = array();
         foreach ($sorted_history_items as $object_type => $objects_and_history_items) {
             foreach ($objects_and_history_items as $object_id => $obj_history_items) {
                 foreach ($obj_history_items as $history_item) {
                     if (isset($objects[$object_type][$object_id])) {
                         $obj = $objects[$object_type][$object_id];
                         $subscribers = $this->_subscribers_for($history_item, $obj);
                         $num_subscribers = sizeof($subscribers);
                         $this->record($obj->title_as_plain_text() . ' (' . $history_item->title_as_plain_text() . "): [{$num_subscribers}] subscribers.");
                         if ($num_subscribers > 0) {
                             foreach ($subscribers as $subscriber) {
                                 /* If the history item was from a pending history item list, make sure to
                                  * only send it to subscribers who actually have the history item
                                  * pending. Otherwise, it might be sent to some subscribers
                                  * multiple times.
                                  */
                                 if (!isset($queued_history_item_ids[$history_item->id]) || $subscriber->is_queued_history_item($history_item->id)) {
                                     /* Give the subscriber a chance to decide whether this particular
                                      * history item should be sent or not. Basic filtering is already
                                      * done when retrieving the subscriber list for an object,
                                      * but this allows more fine-grained filtering (which would
                                      * not be practical in the main query).
                                      */
                                     if ($subscriber->wants_notification($history_item)) {
                                         if (!isset($subscriber_records[$subscriber->email])) {
                                             $sub_rec = new stdClass();
                                             $sub_rec->subscriber = $subscriber;
                                             $sub_rec->num_objects = 0;
                                             $subscriber_records[$subscriber->email] = $sub_rec;
                                         }
                                         /* Organize the history items and objects in each subscriber. Store
                                          * an extra list of all history items in the subscriber
                                          * directly. This will be used later, if the subscriber is
                                          * not yet ready to receive messages.
                                          */
                                         $subscriber_records[$subscriber->email]->history_items[$history_item->id] = $history_item;
                                         $subscriber_records[$subscriber->email]->num_objects += 1;
                                         $subscriber_records[$subscriber->email]->objects[$history_item->access_id][$object_type][$object_id] = new stdClass();
                                         $subscriber_records[$subscriber->email]->objects[$history_item->access_id][$object_type][$object_id]->object = $obj;
                                         $subscriber_records[$subscriber->email]->objects[$history_item->access_id][$object_type][$object_id]->history_items[] = $history_item;
                                     }
                                 }
                             }
                         }
                     } else {
                         $this->record("Object [{$object_type}][{$object_id}] was not found.", Msg_type_warning);
                     }
                 }
             }
         }
         /* Iterate the subscribers, adding the extant history item ids to the subscriber's
          * list in the database. Save each subscriber, so the history item selection is
          * independent of actually sending the messages.
          */
         foreach ($subscriber_records as $subscriber_rec) {
             $subscriber = $subscriber_rec->subscriber;
             if (sizeof($subscriber_rec->history_items)) {
                 $history_item_ids = array_keys($subscriber_rec->history_items);
                 $num_ids = sizeof($history_item_ids);
                 $ids_for_subscriber = join(',', $history_item_ids);
                 $this->record("{$subscriber->email}: [{$num_ids}] subscribed items found.");
                 if ($num_ids) {
                     $this->record("{$subscriber->email}: Queued [{$ids_for_subscriber}].", Msg_type_debug_info);
                 }
                 $subscriber->add_queued_history_items($ids_for_subscriber);
                 if (!$this->testing) {
                     $subscriber->store();
                 }
             }
         }
         /* Since all subscribers now store the history items in which they're interested, we
          * can mark the history items as processed. If there are errors while sending
          * emails, the unsent history items will simply be retrieved with the
          * subscribers on the next publishing execution.
          */
         $this->_update_publication_status_for($history_items);
         /* Now we have a list of subscribers, each with the list of applicable
          * objects and history items. Now that all of the ids have been replaced with
          * objects, we are ready to check subscriber options to build the
          * publisher items that will be sent to the publishing mechanism itself.*/
         foreach ($subscriber_records as $subscriber_rec) {
             $subscriber = $subscriber_rec->subscriber;
             if ($subscriber->ready_for_messages()) {
                 /* Determine whether grouped messaging will be required. */
                 $num_history_items = sizeof($subscriber_rec->history_items);
                 $num_objects = $subscriber_rec->num_objects;
                 if ($subscriber->group_history_items) {
                     $num_items = $num_objects;
                 } else {
                     $num_items = $num_history_items;
                 }
                 if ($subscriber->max_individual_messages && $num_items > $subscriber->max_individual_messages) {
                     /* Multiple messages are required, 'group_history_items' flag will be ignored. */
                     $item = new PUBLISHER_MESSAGE($this, $subscriber);
                     $num_objects_in_message = 0;
                     foreach ($subscriber_rec->objects as $objs_by_folder) {
                         foreach ($objs_by_folder as $obj_types) {
                             foreach ($obj_types as $obj_rec) {
                                 /* Retain the last object record for use if the loop ends and there
                                    is only one object in the message, we can treat it as a normal
                                    single-object message, without the generic title. */
                                 $last_obj_rec = $obj_rec;
                                 if ($subscriber->show_history_items) {
                                     foreach ($obj_rec->history_items as $history_item) {
                                         $item->add_object($history_item);
                                     }
                                 }
                                 $item->add_main_object($obj_rec->object);
                                 $num_objects_in_message += 1;
                                 if ($num_objects_in_message == $subscriber->max_items_per_message) {
                                     $item->num_items = $num_objects_in_message;
                                     if ($num_objects_in_message == 1) {
                                         $item->set_subject($last_obj_rec->object->title_for_history_item($last_obj_rec->history_items[0], $subscriber));
                                     }
                                     $items[] = $item;
                                     $item = new PUBLISHER_MESSAGE($this, $subscriber);
                                     $num_objects_in_message = 0;
                                 }
                             }
                         }
                     }
                     if ($num_objects_in_message) {
                         $item->num_items = $num_objects_in_message;
                         if ($num_objects_in_message == 1) {
                             $item->set_subject($last_obj_rec->object->title_for_history_item($last_obj_rec->history_items[0], $subscriber));
                         }
                         $items[] = $item;
                     }
                 } else {
                     foreach ($subscriber_rec->objects as $objs_by_folder) {
                         foreach ($objs_by_folder as $obj_types) {
                             foreach ($obj_types as $obj_rec) {
                                 if ($subscriber->group_history_items) {
                                     $item = new PUBLISHER_MESSAGE($this, $subscriber);
                                     if ($subscriber->show_history_items) {
                                         foreach ($obj_rec->history_items as $history_item) {
                                             $item->add_object($history_item);
                                         }
                                     }
                                     $item->add_main_object($obj_rec->object);
                                     $item->set_subject($obj_rec->object->title_for_history_item($obj_rec->history_items[0], $subscriber));
                                     $item->num_items = 1;
                                     $items[] = $item;
                                 } else {
                                     foreach ($obj_rec->history_items as $history_item) {
                                         $item = new PUBLISHER_MESSAGE($this, $subscriber);
                                         if ($subscriber->show_history_items) {
                                             $item->add_object($history_item);
                                         }
                                         $item->add_main_object($obj_rec->object);
                                         $item->set_subject($obj_rec->object->title_for_history_item($history_item, $subscriber));
                                         $item->num_items = 1;
                                         $items[] = $item;
                                     }
                                 }
                             }
                         }
                     }
                 }
             }
         }
         /* At the end, we have a single array of PUBLISHER_MESSAGE records,
          * each of which holds a subscriber and a list of objects to publish for
          * that record. This is the format which the publisher accepts
          * internally.
          */
         if (isset($items)) {
             $this->_send_items($items);
         }
     }
 }
コード例 #2
0
 /**
  * Apply default restrictions and tables.
  */
 public function apply_defaults()
 {
     parent::apply_defaults();
     $this->set_select('DISTINCT(subscribers.email), subscribers.*');
     $this->add_table($this->app->table_names->subscriptions . ' subs', 'subscribers.id = subs.subscriber_id');
 }