DefaultProcessor.php

Same filename in other branches
  1. 9 core/modules/aggregator/src/Plugin/aggregator/processor/DefaultProcessor.php

Namespace

Drupal\aggregator\Plugin\aggregator\processor

File

core/modules/aggregator/src/Plugin/aggregator/processor/DefaultProcessor.php

View source
<?php

namespace Drupal\aggregator\Plugin\aggregator\processor;

use Drupal\aggregator\Entity\Item;
use Drupal\aggregator\FeedInterface;
use Drupal\aggregator\FeedStorageInterface;
use Drupal\aggregator\ItemStorageInterface;
use Drupal\aggregator\Plugin\AggregatorPluginSettingsBase;
use Drupal\aggregator\Plugin\ProcessorInterface;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\Core\Form\ConfigFormBaseTrait;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Defines a default processor implementation.
 *
 * Creates lightweight records from feed items.
 *
 * @AggregatorProcessor(
 *   id = "aggregator",
 *   title = @Translation("Default processor"),
 *   description = @Translation("Creates lightweight records from feed items.")
 * )
 */
class DefaultProcessor extends AggregatorPluginSettingsBase implements ProcessorInterface, ContainerFactoryPluginInterface {
    use ConfigFormBaseTrait;
    
    /**
     * Contains the configuration object factory.
     *
     * @var \Drupal\Core\Config\ConfigFactoryInterface
     */
    protected $configFactory;
    
    /**
     * The entity storage for items.
     *
     * @var \Drupal\aggregator\ItemStorageInterface
     */
    protected $itemStorage;
    
    /**
     * The date formatter service.
     *
     * @var \Drupal\Core\Datetime\DateFormatterInterface
     */
    protected $dateFormatter;
    
    /**
     * The messenger.
     *
     * @var \Drupal\Core\Messenger\MessengerInterface
     */
    protected $messenger;
    
    /**
     * Constructs a DefaultProcessor object.
     *
     * @param array $configuration
     *   A configuration array containing information about the plugin instance.
     * @param string $plugin_id
     *   The plugin_id for the plugin instance.
     * @param mixed $plugin_definition
     *   The plugin implementation definition.
     * @param \Drupal\Core\Config\ConfigFactoryInterface $config
     *   The configuration factory object.
     * @param \Drupal\aggregator\ItemStorageInterface $item_storage
     *   The entity storage for feed items.
     * @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
     *   The date formatter service.
     * @param \Drupal\Core\Messenger\MessengerInterface $messenger
     *   The messenger.
     */
    public function __construct(array $configuration, $plugin_id, $plugin_definition, ConfigFactoryInterface $config, ItemStorageInterface $item_storage, DateFormatterInterface $date_formatter, MessengerInterface $messenger) {
        $this->configFactory = $config;
        $this->itemStorage = $item_storage;
        $this->dateFormatter = $date_formatter;
        $this->messenger = $messenger;
        // @todo Refactor aggregator plugins to ConfigEntity so merging
        //   the configuration here is not needed.
        parent::__construct($configuration + $this->getConfiguration(), $plugin_id, $plugin_definition);
    }
    
    /**
     * {@inheritdoc}
     */
    public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
        return new static($configuration, $plugin_id, $plugin_definition, $container->get('config.factory'), $container->get('entity_type.manager')
            ->getStorage('aggregator_item'), $container->get('date.formatter'), $container->get('messenger'));
    }
    
    /**
     * {@inheritdoc}
     */
    protected function getEditableConfigNames() {
        return [
            'aggregator.settings',
        ];
    }
    
    /**
     * {@inheritdoc}
     */
    public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
        $config = $this->config('aggregator.settings');
        $processors = $config->get('processors');
        $info = $this->getPluginDefinition();
        $counts = [
            3,
            5,
            10,
            15,
            20,
            25,
        ];
        $items = array_map(function ($count) {
            return $this->formatPlural($count, '1 item', '@count items');
        }, array_combine($counts, $counts));
        $intervals = [
            3600,
            10800,
            21600,
            32400,
            43200,
            86400,
            172800,
            259200,
            604800,
            1209600,
            2419200,
            4838400,
            9676800,
        ];
        $period = array_map([
            $this->dateFormatter,
            'formatInterval',
        ], array_combine($intervals, $intervals));
        $period[FeedStorageInterface::CLEAR_NEVER] = t('Never');
        $form['processors'][$info['id']] = [];
        // Only wrap into details if there is a basic configuration.
        if (isset($form['basic_conf'])) {
            $form['processors'][$info['id']] = [
                '#type' => 'details',
                '#title' => t('Default processor settings'),
                '#description' => $info['description'],
                '#open' => in_array($info['id'], $processors),
            ];
        }
        $form['processors'][$info['id']]['aggregator_summary_items'] = [
            '#type' => 'select',
            '#title' => t('Number of items shown in listing pages'),
            '#default_value' => $config->get('source.list_max'),
            '#empty_value' => 0,
            '#options' => $items,
        ];
        $form['processors'][$info['id']]['aggregator_clear'] = [
            '#type' => 'select',
            '#title' => t('Discard items older than'),
            '#default_value' => $config->get('items.expire'),
            '#options' => $period,
            '#description' => t('Requires a correctly configured <a href=":cron">cron maintenance task</a>.', [
                ':cron' => Url::fromRoute('system.status')->toString(),
            ]),
        ];
        $lengths = [
            0,
            200,
            400,
            600,
            800,
            1000,
            1200,
            1400,
            1600,
            1800,
            2000,
        ];
        $options = array_map(function ($length) {
            return $length == 0 ? t('Unlimited') : $this->formatPlural($length, '1 character', '@count characters');
        }, array_combine($lengths, $lengths));
        $form['processors'][$info['id']]['aggregator_teaser_length'] = [
            '#type' => 'select',
            '#title' => t('Length of trimmed description'),
            '#default_value' => $config->get('items.teaser_length'),
            '#options' => $options,
            '#description' => t('The maximum number of characters used in the trimmed version of content.'),
        ];
        return $form;
    }
    
    /**
     * {@inheritdoc}
     */
    public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
        $this->configuration['items']['expire'] = $form_state->getValue('aggregator_clear');
        $this->configuration['items']['teaser_length'] = $form_state->getValue('aggregator_teaser_length');
        $this->configuration['source']['list_max'] = $form_state->getValue('aggregator_summary_items');
        // @todo Refactor aggregator plugins to ConfigEntity so this is not needed.
        $this->setConfiguration($this->configuration);
    }
    
    /**
     * {@inheritdoc}
     */
    public function process(FeedInterface $feed) {
        if (!is_array($feed->items)) {
            return;
        }
        foreach ($feed->items as $item) {
            // @todo: The default entity view builder always returns an empty
            //   array, which is ignored in aggregator_save_item() currently. Should
            //   probably be fixed.
            if (empty($item['title'])) {
                continue;
            }
            // Save this item. Try to avoid duplicate entries as much as possible. If
            // we find a duplicate entry, we resolve it and pass along its ID is such
            // that we can update it if needed.
            if (!empty($item['guid'])) {
                $values = [
                    'fid' => $feed->id(),
                    'guid' => $item['guid'],
                ];
            }
            elseif ($item['link'] && $item['link'] != $feed->link && $item['link'] != $feed->url) {
                $values = [
                    'fid' => $feed->id(),
                    'link' => $item['link'],
                ];
            }
            else {
                $values = [
                    'fid' => $feed->id(),
                    'title' => $item['title'],
                ];
            }
            // Try to load an existing entry.
            if ($entry = $this->itemStorage
                ->loadByProperties($values)) {
                $entry = reset($entry);
            }
            else {
                $entry = Item::create([
                    'langcode' => $feed->language()
                        ->getId(),
                ]);
            }
            if ($item['timestamp']) {
                $entry->setPostedTime($item['timestamp']);
            }
            // Make sure the item title and author fit in the 255 varchar column.
            $entry->setTitle(Unicode::truncate($item['title'], 255, TRUE, TRUE));
            $entry->setAuthor(Unicode::truncate($item['author'], 255, TRUE, TRUE));
            $entry->setFeedId($feed->id());
            $entry->setLink($item['link']);
            $entry->setGuid($item['guid']);
            $description = '';
            if (!empty($item['description'])) {
                $description = $item['description'];
            }
            $entry->setDescription($description);
            $entry->save();
        }
    }
    
    /**
     * {@inheritdoc}
     */
    public function delete(FeedInterface $feed) {
        if ($items = $this->itemStorage
            ->loadByFeed($feed->id())) {
            $this->itemStorage
                ->delete($items);
        }
        // @todo This should be moved out to caller with a different message maybe.
        $this->messenger
            ->addStatus(t('The news items from %site have been deleted.', [
            '%site' => $feed->label(),
        ]));
    }
    
    /**
     * Implements \Drupal\aggregator\Plugin\ProcessorInterface::postProcess().
     *
     * Expires items from a feed depending on expiration settings.
     */
    public function postProcess(FeedInterface $feed) {
        $aggregator_clear = $this->configuration['items']['expire'];
        if ($aggregator_clear != FeedStorageInterface::CLEAR_NEVER) {
            // Delete all items that are older than flush item timer.
            $age = REQUEST_TIME - $aggregator_clear;
            $result = $this->itemStorage
                ->getQuery()
                ->condition('fid', $feed->id())
                ->condition('timestamp', $age, '<')
                ->execute();
            if ($result) {
                $entities = $this->itemStorage
                    ->loadMultiple($result);
                $this->itemStorage
                    ->delete($entities);
            }
        }
    }
    
    /**
     * {@inheritdoc}
     */
    public function getConfiguration() {
        return $this->configFactory
            ->get('aggregator.settings')
            ->get();
    }
    
    /**
     * {@inheritdoc}
     */
    public function setConfiguration(array $configuration) {
        $config = $this->config('aggregator.settings');
        foreach ($configuration as $key => $value) {
            $config->set($key, $value);
        }
        $config->save();
    }

}

Classes

Title Deprecated Summary
DefaultProcessor Defines a default processor implementation.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.