Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / web / core / modules / aggregator / src / Plugin / aggregator / processor / DefaultProcessor.php
1 <?php
2
3 namespace Drupal\aggregator\Plugin\aggregator\processor;
4
5 use Drupal\aggregator\Entity\Item;
6 use Drupal\aggregator\FeedInterface;
7 use Drupal\aggregator\ItemStorageInterface;
8 use Drupal\aggregator\Plugin\AggregatorPluginSettingsBase;
9 use Drupal\aggregator\Plugin\ProcessorInterface;
10 use Drupal\Component\Utility\Unicode;
11 use Drupal\Core\Config\ConfigFactoryInterface;
12 use Drupal\Core\Datetime\DateFormatterInterface;
13 use Drupal\Core\Form\ConfigFormBaseTrait;
14 use Drupal\Core\Form\FormStateInterface;
15 use Drupal\Core\Messenger\MessengerInterface;
16 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
17 use Drupal\Core\Routing\UrlGeneratorTrait;
18 use Symfony\Component\DependencyInjection\ContainerInterface;
19
20 /**
21  * Defines a default processor implementation.
22  *
23  * Creates lightweight records from feed items.
24  *
25  * @AggregatorProcessor(
26  *   id = "aggregator",
27  *   title = @Translation("Default processor"),
28  *   description = @Translation("Creates lightweight records from feed items.")
29  * )
30  */
31 class DefaultProcessor extends AggregatorPluginSettingsBase implements ProcessorInterface, ContainerFactoryPluginInterface {
32
33   use ConfigFormBaseTrait;
34   use UrlGeneratorTrait;
35
36   /**
37    * Contains the configuration object factory.
38    *
39    * @var \Drupal\Core\Config\ConfigFactoryInterface
40    */
41   protected $configFactory;
42
43   /**
44    * The entity storage for items.
45    *
46    * @var \Drupal\aggregator\ItemStorageInterface
47    */
48   protected $itemStorage;
49
50   /**
51    * The date formatter service.
52    *
53    * @var \Drupal\Core\Datetime\DateFormatterInterface
54    */
55   protected $dateFormatter;
56
57   /**
58    * The messenger.
59    *
60    * @var \Drupal\Core\Messenger\MessengerInterface
61    */
62   protected $messenger;
63
64   /**
65    * Constructs a DefaultProcessor object.
66    *
67    * @param array $configuration
68    *   A configuration array containing information about the plugin instance.
69    * @param string $plugin_id
70    *   The plugin_id for the plugin instance.
71    * @param mixed $plugin_definition
72    *   The plugin implementation definition.
73    * @param \Drupal\Core\Config\ConfigFactoryInterface $config
74    *   The configuration factory object.
75    * @param \Drupal\aggregator\ItemStorageInterface $item_storage
76    *   The entity storage for feed items.
77    * @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
78    *   The date formatter service.
79    * @param \Drupal\Core\Messenger\MessengerInterface $messenger
80    *   The messenger.
81    */
82   public function __construct(array $configuration, $plugin_id, $plugin_definition, ConfigFactoryInterface $config, ItemStorageInterface $item_storage, DateFormatterInterface $date_formatter, MessengerInterface $messenger) {
83     $this->configFactory = $config;
84     $this->itemStorage = $item_storage;
85     $this->dateFormatter = $date_formatter;
86     $this->messenger = $messenger;
87     // @todo Refactor aggregator plugins to ConfigEntity so merging
88     //   the configuration here is not needed.
89     parent::__construct($configuration + $this->getConfiguration(), $plugin_id, $plugin_definition);
90   }
91
92   /**
93    * {@inheritdoc}
94    */
95   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
96     return new static(
97       $configuration,
98       $plugin_id,
99       $plugin_definition,
100       $container->get('config.factory'),
101       $container->get('entity_type.manager')->getStorage('aggregator_item'),
102       $container->get('date.formatter'),
103       $container->get('messenger')
104     );
105   }
106
107   /**
108    * {@inheritdoc}
109    */
110   protected function getEditableConfigNames() {
111     return ['aggregator.settings'];
112   }
113
114   /**
115    * {@inheritdoc}
116    */
117   public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
118     $config = $this->config('aggregator.settings');
119     $processors = $config->get('processors');
120     $info = $this->getPluginDefinition();
121     $counts = [3, 5, 10, 15, 20, 25];
122     $items = array_map(function ($count) {
123       return $this->formatPlural($count, '1 item', '@count items');
124     }, array_combine($counts, $counts));
125     $intervals = [3600, 10800, 21600, 32400, 43200, 86400, 172800, 259200, 604800, 1209600, 2419200, 4838400, 9676800];
126     $period = array_map([$this->dateFormatter, 'formatInterval'], array_combine($intervals, $intervals));
127     $period[AGGREGATOR_CLEAR_NEVER] = t('Never');
128
129     $form['processors'][$info['id']] = [];
130     // Only wrap into details if there is a basic configuration.
131     if (isset($form['basic_conf'])) {
132       $form['processors'][$info['id']] = [
133         '#type' => 'details',
134         '#title' => t('Default processor settings'),
135         '#description' => $info['description'],
136         '#open' => in_array($info['id'], $processors),
137       ];
138     }
139
140     $form['processors'][$info['id']]['aggregator_summary_items'] = [
141       '#type' => 'select',
142       '#title' => t('Number of items shown in listing pages'),
143       '#default_value' => $config->get('source.list_max'),
144       '#empty_value' => 0,
145       '#options' => $items,
146     ];
147
148     $form['processors'][$info['id']]['aggregator_clear'] = [
149       '#type' => 'select',
150       '#title' => t('Discard items older than'),
151       '#default_value' => $config->get('items.expire'),
152       '#options' => $period,
153       '#description' => t('Requires a correctly configured <a href=":cron">cron maintenance task</a>.', [':cron' => $this->url('system.status')]),
154     ];
155
156     $lengths = [0, 200, 400, 600, 800, 1000, 1200, 1400, 1600, 1800, 2000];
157     $options = array_map(function ($length) {
158       return ($length == 0) ? t('Unlimited') : $this->formatPlural($length, '1 character', '@count characters');
159     }, array_combine($lengths, $lengths));
160
161     $form['processors'][$info['id']]['aggregator_teaser_length'] = [
162       '#type' => 'select',
163       '#title' => t('Length of trimmed description'),
164       '#default_value' => $config->get('items.teaser_length'),
165       '#options' => $options,
166       '#description' => t('The maximum number of characters used in the trimmed version of content.'),
167     ];
168     return $form;
169   }
170
171   /**
172    * {@inheritdoc}
173    */
174   public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
175     $this->configuration['items']['expire'] = $form_state->getValue('aggregator_clear');
176     $this->configuration['items']['teaser_length'] = $form_state->getValue('aggregator_teaser_length');
177     $this->configuration['source']['list_max'] = $form_state->getValue('aggregator_summary_items');
178     // @todo Refactor aggregator plugins to ConfigEntity so this is not needed.
179     $this->setConfiguration($this->configuration);
180   }
181
182   /**
183    * {@inheritdoc}
184    */
185   public function process(FeedInterface $feed) {
186     if (!is_array($feed->items)) {
187       return;
188     }
189     foreach ($feed->items as $item) {
190       // @todo: The default entity view builder always returns an empty
191       //   array, which is ignored in aggregator_save_item() currently. Should
192       //   probably be fixed.
193       if (empty($item['title'])) {
194         continue;
195       }
196
197       // Save this item. Try to avoid duplicate entries as much as possible. If
198       // we find a duplicate entry, we resolve it and pass along its ID is such
199       // that we can update it if needed.
200       if (!empty($item['guid'])) {
201         $values = ['fid' => $feed->id(), 'guid' => $item['guid']];
202       }
203       elseif ($item['link'] && $item['link'] != $feed->link && $item['link'] != $feed->url) {
204         $values = ['fid' => $feed->id(), 'link' => $item['link']];
205       }
206       else {
207         $values = ['fid' => $feed->id(), 'title' => $item['title']];
208       }
209
210       // Try to load an existing entry.
211       if ($entry = entity_load_multiple_by_properties('aggregator_item', $values)) {
212         $entry = reset($entry);
213       }
214       else {
215         $entry = Item::create(['langcode' => $feed->language()->getId()]);
216       }
217       if ($item['timestamp']) {
218         $entry->setPostedTime($item['timestamp']);
219       }
220
221       // Make sure the item title and author fit in the 255 varchar column.
222       $entry->setTitle(Unicode::truncate($item['title'], 255, TRUE, TRUE));
223       $entry->setAuthor(Unicode::truncate($item['author'], 255, TRUE, TRUE));
224
225       $entry->setFeedId($feed->id());
226       $entry->setLink($item['link']);
227       $entry->setGuid($item['guid']);
228
229       $description = '';
230       if (!empty($item['description'])) {
231         $description = $item['description'];
232       }
233       $entry->setDescription($description);
234
235       $entry->save();
236     }
237   }
238
239   /**
240    * {@inheritdoc}
241    */
242   public function delete(FeedInterface $feed) {
243     if ($items = $this->itemStorage->loadByFeed($feed->id())) {
244       $this->itemStorage->delete($items);
245     }
246     // @todo This should be moved out to caller with a different message maybe.
247     $this->messenger->addStatus(t('The news items from %site have been deleted.', ['%site' => $feed->label()]));
248   }
249
250   /**
251    * Implements \Drupal\aggregator\Plugin\ProcessorInterface::postProcess().
252    *
253    * Expires items from a feed depending on expiration settings.
254    */
255   public function postProcess(FeedInterface $feed) {
256     $aggregator_clear = $this->configuration['items']['expire'];
257
258     if ($aggregator_clear != AGGREGATOR_CLEAR_NEVER) {
259       // Delete all items that are older than flush item timer.
260       $age = REQUEST_TIME - $aggregator_clear;
261       $result = $this->itemStorage->getQuery()
262         ->condition('fid', $feed->id())
263         ->condition('timestamp', $age, '<')
264         ->execute();
265       if ($result) {
266         $entities = $this->itemStorage->loadMultiple($result);
267         $this->itemStorage->delete($entities);
268       }
269     }
270   }
271
272   /**
273    * {@inheritdoc}
274    */
275   public function getConfiguration() {
276     return $this->configFactory->get('aggregator.settings')->get();
277   }
278
279   /**
280    * {@inheritdoc}
281    */
282   public function setConfiguration(array $configuration) {
283     $config = $this->config('aggregator.settings');
284     foreach ($configuration as $key => $value) {
285       $config->set($key, $value);
286     }
287     $config->save();
288   }
289
290 }