You are here

class FeedsCommentProcessor in Feeds Comment Processor 6

Same name and namespace in other branches
  1. 7 FeedsCommentProcessor.inc \FeedsCommentProcessor

Creates comments from feed items.

Hierarchy

Expanded class hierarchy of FeedsCommentProcessor

1 string reference to 'FeedsCommentProcessor'
feeds_comment_processor_feeds_plugins in ./feeds_comment_processor.module
Implementation of hook_feeds_plugins().

File

./FeedsCommentProcessor.inc, line 20
Class definition of FeedsCommentProcessor.

View source
class FeedsCommentProcessor extends FeedsProcessor {

  /**
   * Implementation of FeedsProcessor::process().
   */
  public function process(FeedsImportBatch $batch, FeedsSource $source) {

    // Keep track of processed items in this pass.
    $processed = 0;
    if (!$batch
      ->getTotal(FEEDS_PROCESSING)) {
      $batch
        ->setTotal(FEEDS_PROCESSING, $batch
        ->getItemCount());
    }
    while ($item = $batch
      ->shiftItem()) {

      // Create/update if item does not exist or update existing is enabled.
      if (!($cid = $this
        ->existingItemId($batch, $source)) || $this->config['update_existing'] != FEEDS_SKIP_EXISTING) {

        // Only proceed if item has actually changed.
        $hash = $this
          ->hash($item);
        if (!empty($cid) && $hash == $this
          ->getHash($cid)) {
          continue;
        }
        $comment = $this
          ->buildComment($cid, $source->feed_nid);
        $comment->feeds_comment_item->hash = $hash;

        // Map and save comment. If errors occur don't stop but report them.
        try {
          $this
            ->map($batch, $comment);
          if (empty($comment->nid)) {
            throw new Exception("Unable create comment with empty NID");
          }
          if ($this->config['authorize']) {
            $account = user_load($comment->uid);
            if (!user_access('post comments')) {
              throw new Exception('User ' . $account->uid . ' not authorized to post comments.');
            }
          }
          $node = node_load($comment->nid);
          if ($node->comment != 2) {
            throw new Exception('Comments are not allowed for this node.');
          }
          _feeds_comment_save((array) $comment);
          if (!empty($cid)) {
            $batch->updated++;
          }
          else {
            $batch->created++;
          }
        } catch (Exception $e) {
          drupal_set_message($e
            ->getMessage(), 'warning');
          watchdog('feeds', $e
            ->getMessage(), array(), WATCHDOG_WARNING);
        }
      }
      $processed++;
      if ($processed >= variable_get('feeds_comment_batch_size', FEEDS_COMMENT_BATCH_SIZE)) {
        $batch
          ->setProgress(FEEDS_PROCESSING, $batch->created + $batch->updated);
        return;
      }
    }

    // Set messages.
    if ($batch->created) {
      drupal_set_message(format_plural($batch->created, 'Created @number comment', 'Created @number comments.', array(
        '@number' => $batch->created,
      )));
    }
    elseif ($batch->updated) {
      drupal_set_message(format_plural($batch->updated, 'Updated @number comment.', 'Updated @number comments.', array(
        '@number' => $batch->updated,
      )));
    }
    else {
      drupal_set_message(t('There are no new comments.'));
    }
    $batch
      ->setProgress(FEEDS_PROCESSING, FEEDS_BATCH_COMPLETE);
  }

  /**
   * Implementation of FeedsProcessor::clear().
   */
  public function clear(FeedsBatch $batch, FeedsSource $source) {
    if (!$batch
      ->getTotal(FEEDS_CLEARING)) {
      $total = db_result(db_query("SELECT COUNT(cid) FROM {feeds_comment_item} WHERE id = '%s' AND feed_nid = %d", $source->id, $source->feed_nid));
      $batch
        ->setTotal(FEEDS_CLEARING, $total);
    }
    $result = db_query_range("SELECT cid FROM {feeds_comment_item} WHERE id = '%s' AND feed_nid = %d", $source->id, $source->feed_nid, 0, variable_get('feeds_comment_batch_size', FEEDS_COMMENT_BATCH_SIZE));
    while ($comment = db_fetch_object($result)) {
      _feeds_comment_delete($comment->cid);
      $batch->deleted++;
    }
    if (db_result(db_query_range("SELECT cid FROM {feeds_comment_item} WHERE id = '%s' AND feed_nid = %d", $source->id, $source->feed_nid, 0, 1))) {
      $batch
        ->setProgress(FEEDS_CLEARING, $batch->deleted);
      return;
    }

    // Set message.
    drupal_get_messages('status');
    if ($batch->deleted) {
      drupal_set_message(format_plural($batch->deleted, 'Deleted @number comment.', 'Deleted @number comments.', array(
        '@number' => $batch->deleted,
      )));
    }
    else {
      drupal_set_message(t('There is no content to be deleted.'));
    }
    $batch
      ->setProgress(FEEDS_CLEARING, FEEDS_BATCH_COMPLETE);
  }

  /**
   * Implement expire().
   */
  public function expire($time = NULL) {
    if ($time === NULL) {
      $time = $this
        ->expiryTime();
    }
    if ($time == FEEDS_EXPIRE_NEVER) {
      return;
    }
    $result = db_query_range("SELECT c.cid FROM {comments} c INNER JOIN {feeds_comment_item} fci ON c.cid = fci.cid WHERE fci.id = '%s' AND c.timestamp < %d", $this->id, FEEDS_REQUEST_TIME - $time, 0, variable_get('feeds_comment_batch_size', FEEDS_COMMENT_BATCH_SIZE));
    while ($comment = db_fetch_object($result)) {
      _feeds_comment_delete($comment->cid);
    }
    if (db_result(db_query_range("SELECT c.cid FROM {comment} c INNER JOIN {feeds_comment_item} fci ON c.cid = fci.cid WHERE fci.id = '%s' AND c.timestamp < %d", $this->id, FEEDS_REQUEST_TIME - $time, 0, 1))) {
      return FEEDS_BATCH_ACTIVE;
    }
    return FEEDS_BATCH_COMPLETE;
  }

  /**
   * Return expiry time.
   */
  public function expiryTime() {
    return $this->config['expire'];
  }

  /**
   * Override parent::configDefaults().
   */
  public function configDefaults() {
    return array(
      'input_format' => FILTER_FORMAT_DEFAULT,
      'update_existing' => FEEDS_SKIP_EXISTING,
      'expire' => FEEDS_EXPIRE_NEVER,
      'mappings' => array(),
      'author' => 0,
      'authorize' => 0,
    );
  }

  /**
   * Override parent::configForm().
   */
  public function configForm(&$form_state) {
    $form = array();
    $format_options = array(
      FILTER_FORMAT_DEFAULT => t('Default format'),
    );
    $formats = filter_formats();
    foreach ($formats as $format) {
      $format_options[$format->format] = $format->name;
    }
    $form['input_format'] = array(
      '#type' => 'select',
      '#title' => t('Input format'),
      '#description' => t('Select the input format for the comments to be created.'),
      '#options' => $format_options,
      '#default_value' => $this->config['input_format'],
    );
    $author = user_load(array(
      'uid' => $this->config['author'],
    ));
    $form['author'] = array(
      '#type' => 'textfield',
      '#title' => t('Author'),
      '#description' => t('Select the author of the comments to be created - leave empty to assign "anonymous".'),
      '#autocomplete_path' => 'user/autocomplete',
      '#default_value' => empty($author->name) ? 'anonymous' : check_plain($author->name),
    );
    $form['authorize'] = array(
      '#type' => 'checkbox',
      '#title' => t('Authorize'),
      '#description' => t('Check that the author has permission to create the node.'),
      '#default_value' => $this->config['authorize'],
    );
    $period = drupal_map_assoc(array(
      FEEDS_EXPIRE_NEVER,
      3600,
      10800,
      21600,
      43200,
      86400,
      259200,
      604800,
      604800 * 4,
      604800 * 12,
      604800 * 24,
      31536000,
    ), 'feeds_format_expire');
    $form['expire'] = array(
      '#type' => 'select',
      '#title' => t('Expire comments'),
      '#options' => $period,
      '#description' => t('Select after how much time comments should be deleted. The comment\'s published date will be used for determining the comment\'s age, see Mapping settings.'),
      '#default_value' => $this->config['expire'],
    );
    $form['update_existing'] = array(
      '#type' => 'radios',
      '#title' => t('Update existing comments'),
      '#description' => t('Select how existing comments should be updated. Existing comments will be determined using mappings that are a "unique target".'),
      '#options' => array(
        FEEDS_SKIP_EXISTING => 'Do not update existing comments',
        FEEDS_REPLACE_EXISTING => 'Replace existing comments',
        FEEDS_UPDATE_EXISTING => 'Update existing comments (slower than replacing them)',
      ),
      '#default_value' => $this->config['update_existing'],
    );
    return $form;
  }

  /**
   * Override parent::configFormValidate().
   */
  public function configFormValidate(&$values) {
    if ($author = user_load(array(
      'name' => $values['author'],
    ))) {
      $values['author'] = $author->uid;
    }
    else {
      $values['author'] = 0;
    }
  }

  /**
   * Override setTargetElement to operate on a target item that is a comment.
   */
  public function setTargetElement($target_comment, $target_element, $value) {
    if (in_array($target_element, array(
      'guid',
    ))) {
      $target_comment->feeds_comment_item->{$target_element} = $value;
    }
    elseif (array_key_exists($target_element, $this
      ->getMappingTargets())) {
      $target_comment->{$target_element} = $value;
    }
  }

  /**
   * Return available mapping targets.
   */
  public function getMappingTargets() {
    $targets = array(
      'pid' => array(
        'name' => t('Parent ID'),
        'description' => t('The cid to which this comment is a reply.'),
      ),
      'nid' => array(
        'name' => t('Node ID'),
        'description' => t('The nid to which this comment is a reply.'),
      ),
      'uid' => array(
        'name' => t('User ID'),
        'description' => t('The Drupal user ID of the comment author.'),
      ),
      'subject' => array(
        'name' => t('Title'),
        'description' => t('The title of the comment.'),
      ),
      'comment' => array(
        'name' => t('Comment'),
        'description' => t('The comment body.'),
      ),
      'hostname' => array(
        'name' => t('Hostname'),
        'description' => t('The author\'s host name.'),
      ),
      'timestamp' => array(
        'name' => t('Published date'),
        'description' => t('The UNIX time when a comment has been saved.'),
      ),
      'status' => array(
        'name' => t('Published status'),
        'description' => t('The published status of a comment. (0 = Not Published, 1 = Published)'),
      ),
      'name' => array(
        'name' => t('Name'),
        'description' => t('The comment author\'s name.'),
      ),
      'mail' => array(
        'name' => t('Email'),
        'description' => t('The comment author\'s e-mail address.'),
      ),
      'homepage' => array(
        'name' => t('Homepage'),
        'description' => t('The comment author\'s home page address'),
      ),
      'guid' => array(
        'name' => t('GUID'),
        'description' => t('The external GUID of the comment. E. g. the feed item GUID in the case of a syndication feed. May be unique.'),
        'optional_unique' => TRUE,
      ),
    );

    // Let other modules expose mapping targets.
    self::loadMappers();
    drupal_alter('feeds_comment_processor_targets', $targets);
    return $targets;
  }

  /**
   * Get cid of an existing feed item comment if available.
   */
  protected function existingItemId($source_item, FeedsSource $source) {

    // Iterate through all unique targets and test whether they do already
    // exist in the database.
    foreach ($this
      ->uniqueTargets($source_item) as $target => $value) {
      switch ($target) {
        case 'guid':
          $cid = db_result(db_query("SELECT cid FROM {feeds_comment_item} WHERE feed_nid = %d AND id = '%s' AND guid = '%s'", $source->feed_nid, $source->id, $value));
          break;
      }
      if ($cid) {

        // Return with the first nid found.
        return $cid;
      }
    }
    return 0;
  }

  /**
   * Creates a new comment object in memory and returns it.
   */
  protected function buildComment($cid, $feed_nid) {
    $comment = new stdClass();
    if (empty($cid)) {
      $comment->created = FEEDS_REQUEST_TIME;
      $populate = TRUE;
    }
    else {
      if ($this->config['update_existing'] == FEEDS_UPDATE_EXISTING) {
        $comment = _comment_load($cid);
      }
      else {
        $comment->cid = $cid;
        $populate = TRUE;
      }
    }
    if ($populate) {
      $comment->timestamp = FEEDS_REQUEST_TIME;
      $comment->format = $this->config['input_format'];
      $comment->feeds_comment_item = new stdClass();
      $comment->feeds_comment_item->id = $this->id;
      $comment->feeds_comment_item->imported = FEEDS_REQUEST_TIME;
      $comment->feeds_comment_item->feed_nid = $feed_nid;
      $comment->feeds_comment_item->guid = '';
      $comment->uid = $this->config['author'];
      $account = user_load(array(
        'uid' => $comment->uid,
      ));
      $comment->name = $account->name;
      $comment->mail = $account->mail;
      $comment->status = 0;
      $comment->pid = 0;
      $comment->hostname = '127.0.0.1';
    }
    return $comment;
  }

  /**
   * Create MD5 hash of item and mappings array.
   *
   * Include mappings as a change in mappings may have an affect on the item
   * produced.
   *
   * @return Always returns a hash, even with empty, NULL, FALSE:
   *  Empty arrays return 40cd750bba9870f18aada2478b24840a
   *  Empty/NULL/FALSE strings return d41d8cd98f00b204e9800998ecf8427e
   */
  protected function hash($item) {
    static $serialized_mappings;
    if (!$serialized_mappings) {
      $serialized_mappings = serialize($this->config['mappings']);
    }
    return hash('md5', serialize($item) . $serialized_mappings);
  }

  /**
   * Retrieve MD5 hash of $cid from DB.
   * @return Empty string if no item is found, hash otherwise.
   */
  protected function getHash($cid) {
    $hash = db_result(db_query("SELECT hash FROM {feeds_comment_item} WHERE cid = %d", $cid));
    if ($hash) {

      // Return with the hash.
      return $hash;
    }
    return '';
  }

}

Members

Namesort descending Modifiers Type Description Overrides
FeedsCommentProcessor::buildComment protected function Creates a new comment object in memory and returns it.
FeedsCommentProcessor::clear public function Implementation of FeedsProcessor::clear(). Overrides FeedsProcessor::clear
FeedsCommentProcessor::configDefaults public function Override parent::configDefaults(). Overrides FeedsProcessor::configDefaults
FeedsCommentProcessor::configForm public function Override parent::configForm(). Overrides FeedsConfigurable::configForm
FeedsCommentProcessor::configFormValidate public function Override parent::configFormValidate(). Overrides FeedsConfigurable::configFormValidate
FeedsCommentProcessor::existingItemId protected function Get cid of an existing feed item comment if available. Overrides FeedsProcessor::existingItemId
FeedsCommentProcessor::expire public function Implement expire(). Overrides FeedsProcessor::expire
FeedsCommentProcessor::expiryTime public function Return expiry time. Overrides FeedsProcessor::expiryTime
FeedsCommentProcessor::getHash protected function Retrieve MD5 hash of $cid from DB.
FeedsCommentProcessor::getMappingTargets public function Return available mapping targets. Overrides FeedsProcessor::getMappingTargets
FeedsCommentProcessor::hash protected function Create MD5 hash of item and mappings array.
FeedsCommentProcessor::process public function Implementation of FeedsProcessor::process(). Overrides FeedsProcessor::process
FeedsCommentProcessor::setTargetElement public function Override setTargetElement to operate on a target item that is a comment. Overrides FeedsProcessor::setTargetElement
FeedsConfigurable::$config protected property
FeedsConfigurable::$disabled protected property CTools export enabled status of this object.
FeedsConfigurable::$export_type protected property
FeedsConfigurable::$id protected property
FeedsConfigurable::addConfig public function Similar to setConfig but adds to existing configuration. 1
FeedsConfigurable::configFormSubmit public function Submission handler for configForm(). 3
FeedsConfigurable::copy public function Copy a configuration. 1
FeedsConfigurable::existing public function Determine whether this object is persistent and enabled. I. e. it is defined either in code or in the database and it is enabled. 1
FeedsConfigurable::getConfig public function Implementation of getConfig(). 1
FeedsConfigurable::instance public static function Instantiate a FeedsConfigurable object. 1
FeedsConfigurable::setConfig public function Set configuration. 1
FeedsConfigurable::__get public function Override magic method __get(). Make sure that $this->config goes through getConfig()
FeedsConfigurable::__isset public function Override magic method __isset(). This is needed due to overriding __get().
FeedsPlugin::hasSourceConfig public function Returns TRUE if $this->sourceForm() returns a form. Overrides FeedsSourceInterface::hasSourceConfig
FeedsPlugin::loadMappers protected static function Loads on-behalf implementations from mappers/ directory.
FeedsPlugin::save public function Save changes to the configuration of this object. Delegate saving to parent (= Feed) which will collect information from this object by way of getConfig() and store it. Overrides FeedsConfigurable::save
FeedsPlugin::sourceDefaults public function Implementation of FeedsSourceInterface::sourceDefaults(). Overrides FeedsSourceInterface::sourceDefaults 1
FeedsPlugin::sourceDelete public function A source is being deleted. Overrides FeedsSourceInterface::sourceDelete 1
FeedsPlugin::sourceForm public function Callback methods, exposes source form. Overrides FeedsSourceInterface::sourceForm 3
FeedsPlugin::sourceFormValidate public function Validation handler for sourceForm. Overrides FeedsSourceInterface::sourceFormValidate 2
FeedsPlugin::sourceSave public function A source is being saved. Overrides FeedsSourceInterface::sourceSave 1
FeedsPlugin::__construct protected function Constructor. Overrides FeedsConfigurable::__construct
FeedsProcessor::getMappings public function Get mappings.
FeedsProcessor::map protected function Execute mapping on an item. 3
FeedsProcessor::uniqueTargets protected function Utility function that iterates over a target array and retrieves all sources that are unique.