1<?php 2 3namespace Drupal\aggregator\Entity; 4 5use Drupal\aggregator\FeedStorageInterface; 6use Drupal\Core\Entity\ContentEntityBase; 7use Drupal\Core\Entity\EntityTypeInterface; 8use Drupal\Core\Field\BaseFieldDefinition; 9use Drupal\Core\Entity\EntityStorageInterface; 10use Drupal\aggregator\FeedInterface; 11 12/** 13 * Defines the aggregator feed entity class. 14 * 15 * @ContentEntityType( 16 * id = "aggregator_feed", 17 * label = @Translation("Aggregator feed"), 18 * label_collection = @Translation("Aggregator feeds"), 19 * label_singular = @Translation("aggregator feed"), 20 * label_plural = @Translation("aggregator feeds"), 21 * label_count = @PluralTranslation( 22 * singular = "@count aggregator feed", 23 * plural = "@count aggregator feeds", 24 * ), 25 * handlers = { 26 * "storage" = "Drupal\aggregator\FeedStorage", 27 * "storage_schema" = "Drupal\aggregator\FeedStorageSchema", 28 * "view_builder" = "Drupal\aggregator\FeedViewBuilder", 29 * "access" = "Drupal\aggregator\FeedAccessControlHandler", 30 * "views_data" = "Drupal\aggregator\AggregatorFeedViewsData", 31 * "form" = { 32 * "default" = "Drupal\aggregator\FeedForm", 33 * "delete" = "Drupal\aggregator\Form\FeedDeleteForm", 34 * "delete_items" = "Drupal\aggregator\Form\FeedItemsDeleteForm", 35 * }, 36 * "route_provider" = { 37 * "html" = "Drupal\aggregator\FeedHtmlRouteProvider", 38 * }, 39 * }, 40 * links = { 41 * "canonical" = "/aggregator/sources/{aggregator_feed}", 42 * "edit-form" = "/aggregator/sources/{aggregator_feed}/configure", 43 * "delete-form" = "/aggregator/sources/{aggregator_feed}/delete", 44 * }, 45 * field_ui_base_route = "aggregator.admin_overview", 46 * base_table = "aggregator_feed", 47 * render_cache = FALSE, 48 * entity_keys = { 49 * "id" = "fid", 50 * "label" = "title", 51 * "langcode" = "langcode", 52 * "uuid" = "uuid", 53 * } 54 * ) 55 */ 56class Feed extends ContentEntityBase implements FeedInterface { 57 58 /** 59 * {@inheritdoc} 60 */ 61 public function label() { 62 return $this->get('title')->value; 63 } 64 65 /** 66 * {@inheritdoc} 67 */ 68 public function deleteItems() { 69 \Drupal::service('aggregator.items.importer')->delete($this); 70 71 // Reset feed. 72 $this->setLastCheckedTime(0); 73 $this->setHash(''); 74 $this->setEtag(''); 75 $this->setLastModified(0); 76 $this->save(); 77 78 return $this; 79 } 80 81 /** 82 * {@inheritdoc} 83 */ 84 public function refreshItems() { 85 $success = \Drupal::service('aggregator.items.importer')->refresh($this); 86 87 // Regardless of successful or not, indicate that it has been checked. 88 $this->setLastCheckedTime(REQUEST_TIME); 89 $this->setQueuedTime(0); 90 $this->save(); 91 92 return $success; 93 } 94 95 /** 96 * {@inheritdoc} 97 */ 98 public static function preCreate(EntityStorageInterface $storage, array &$values) { 99 $values += [ 100 'link' => '', 101 'description' => '', 102 'image' => '', 103 ]; 104 } 105 106 /** 107 * {@inheritdoc} 108 */ 109 public static function preDelete(EntityStorageInterface $storage, array $entities) { 110 foreach ($entities as $entity) { 111 // Notify processors to delete stored items. 112 \Drupal::service('aggregator.items.importer')->delete($entity); 113 } 114 } 115 116 /** 117 * {@inheritdoc} 118 */ 119 public static function postDelete(EntityStorageInterface $storage, array $entities) { 120 parent::postDelete($storage, $entities); 121 if (\Drupal::moduleHandler()->moduleExists('block')) { 122 // Make sure there are no active blocks for these feeds. 123 $ids = \Drupal::entityQuery('block') 124 ->condition('plugin', 'aggregator_feed_block') 125 ->condition('settings.feed', array_keys($entities)) 126 ->execute(); 127 if ($ids) { 128 $block_storage = \Drupal::entityTypeManager()->getStorage('block'); 129 $block_storage->delete($block_storage->loadMultiple($ids)); 130 } 131 } 132 } 133 134 /** 135 * {@inheritdoc} 136 */ 137 public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { 138 /** @var \Drupal\Core\Field\BaseFieldDefinition[] $fields */ 139 $fields = parent::baseFieldDefinitions($entity_type); 140 141 $fields['fid']->setLabel(t('Feed ID')) 142 ->setDescription(t('The ID of the aggregator feed.')); 143 144 $fields['uuid']->setDescription(t('The aggregator feed UUID.')); 145 146 $fields['langcode']->setLabel(t('Language code')) 147 ->setDescription(t('The feed language code.')); 148 149 $fields['title'] = BaseFieldDefinition::create('string') 150 ->setLabel(t('Title')) 151 ->setDescription(t('The name of the feed (or the name of the website providing the feed).')) 152 ->setRequired(TRUE) 153 ->setSetting('max_length', 255) 154 ->setDisplayOptions('form', [ 155 'type' => 'string_textfield', 156 'weight' => -5, 157 ]) 158 ->setDisplayConfigurable('form', TRUE) 159 ->addConstraint('FeedTitle'); 160 161 $fields['url'] = BaseFieldDefinition::create('uri') 162 ->setLabel(t('URL')) 163 ->setDescription(t('The fully-qualified URL of the feed.')) 164 ->setRequired(TRUE) 165 ->setDisplayOptions('form', [ 166 'type' => 'uri', 167 'weight' => -3, 168 ]) 169 ->setDisplayConfigurable('form', TRUE) 170 ->addConstraint('FeedUrl'); 171 172 $intervals = [900, 1800, 3600, 7200, 10800, 21600, 32400, 43200, 64800, 86400, 172800, 259200, 604800, 1209600, 2419200]; 173 $period = array_map([\Drupal::service('date.formatter'), 'formatInterval'], array_combine($intervals, $intervals)); 174 $period[FeedStorageInterface::CLEAR_NEVER] = t('Never'); 175 176 $fields['refresh'] = BaseFieldDefinition::create('list_integer') 177 ->setLabel(t('Update interval')) 178 ->setDescription(t('The length of time between feed updates. Requires a correctly configured cron maintenance task.')) 179 ->setDefaultValue(3600) 180 ->setSetting('unsigned', TRUE) 181 ->setRequired(TRUE) 182 ->setSetting('allowed_values', $period) 183 ->setDisplayOptions('form', [ 184 'type' => 'options_select', 185 'weight' => -2, 186 ]) 187 ->setDisplayConfigurable('form', TRUE); 188 189 $fields['checked'] = BaseFieldDefinition::create('timestamp') 190 ->setLabel(t('Checked', [], ['context' => 'Examined'])) 191 ->setDescription(t('Last time feed was checked for new items, as Unix timestamp.')) 192 ->setDefaultValue(0) 193 ->setDisplayOptions('view', [ 194 'label' => 'inline', 195 'type' => 'timestamp_ago', 196 'weight' => 1, 197 ]) 198 ->setDisplayConfigurable('view', TRUE); 199 200 $fields['queued'] = BaseFieldDefinition::create('timestamp') 201 ->setLabel(t('Queued')) 202 ->setDescription(t('Time when this feed was queued for refresh, 0 if not queued.')) 203 ->setDefaultValue(0); 204 205 $fields['link'] = BaseFieldDefinition::create('uri') 206 ->setLabel(t('URL')) 207 ->setDescription(t('The link of the feed.')) 208 ->setDisplayOptions('view', [ 209 'label' => 'inline', 210 'weight' => 4, 211 ]) 212 ->setDisplayConfigurable('view', TRUE); 213 214 $fields['description'] = BaseFieldDefinition::create('string_long') 215 ->setLabel(t('Description')) 216 ->setDescription(t("The parent website's description that comes from the @description element in the feed.", ['@description' => '<description>'])); 217 218 $fields['image'] = BaseFieldDefinition::create('uri') 219 ->setLabel(t('Image')) 220 ->setDescription(t('An image representing the feed.')); 221 222 $fields['hash'] = BaseFieldDefinition::create('string') 223 ->setLabel(t('Hash')) 224 ->setSetting('is_ascii', TRUE) 225 ->setDescription(t('Calculated hash of the feed data, used for validating cache.')); 226 227 $fields['etag'] = BaseFieldDefinition::create('string') 228 ->setLabel(t('Etag')) 229 ->setDescription(t('Entity tag HTTP response header, used for validating cache.')); 230 231 // This is updated by the fetcher and not when the feed is saved, therefore 232 // it's a timestamp and not a changed field. 233 $fields['modified'] = BaseFieldDefinition::create('timestamp') 234 ->setLabel(t('Modified')) 235 ->setDescription(t('When the feed was last modified, as a Unix timestamp.')); 236 237 return $fields; 238 } 239 240 /** 241 * {@inheritdoc} 242 */ 243 public function getUrl() { 244 return $this->get('url')->value; 245 } 246 247 /** 248 * {@inheritdoc} 249 */ 250 public function getRefreshRate() { 251 return $this->get('refresh')->value; 252 } 253 254 /** 255 * {@inheritdoc} 256 */ 257 public function getLastCheckedTime() { 258 return $this->get('checked')->value; 259 } 260 261 /** 262 * {@inheritdoc} 263 */ 264 public function getQueuedTime() { 265 return $this->get('queued')->value; 266 } 267 268 /** 269 * {@inheritdoc} 270 */ 271 public function getWebsiteUrl() { 272 return $this->get('link')->value; 273 } 274 275 /** 276 * {@inheritdoc} 277 */ 278 public function getDescription() { 279 return $this->get('description')->value; 280 } 281 282 /** 283 * {@inheritdoc} 284 */ 285 public function getImage() { 286 return $this->get('image')->value; 287 } 288 289 /** 290 * {@inheritdoc} 291 */ 292 public function getHash() { 293 return $this->get('hash')->value; 294 } 295 296 /** 297 * {@inheritdoc} 298 */ 299 public function getEtag() { 300 return $this->get('etag')->value; 301 } 302 303 /** 304 * {@inheritdoc} 305 */ 306 public function getLastModified() { 307 return $this->get('modified')->value; 308 } 309 310 /** 311 * {@inheritdoc} 312 */ 313 public function setTitle($title) { 314 $this->set('title', $title); 315 return $this; 316 } 317 318 /** 319 * {@inheritdoc} 320 */ 321 public function setUrl($url) { 322 $this->set('url', $url); 323 return $this; 324 } 325 326 /** 327 * {@inheritdoc} 328 */ 329 public function setRefreshRate($refresh) { 330 $this->set('refresh', $refresh); 331 return $this; 332 } 333 334 /** 335 * {@inheritdoc} 336 */ 337 public function setLastCheckedTime($checked) { 338 $this->set('checked', $checked); 339 return $this; 340 } 341 342 /** 343 * {@inheritdoc} 344 */ 345 public function setQueuedTime($queued) { 346 $this->set('queued', $queued); 347 return $this; 348 } 349 350 /** 351 * {@inheritdoc} 352 */ 353 public function setWebsiteUrl($link) { 354 $this->set('link', $link); 355 return $this; 356 } 357 358 /** 359 * {@inheritdoc} 360 */ 361 public function setDescription($description) { 362 $this->set('description', $description); 363 return $this; 364 } 365 366 /** 367 * {@inheritdoc} 368 */ 369 public function setImage($image) { 370 $this->set('image', $image); 371 return $this; 372 } 373 374 /** 375 * {@inheritdoc} 376 */ 377 public function setHash($hash) { 378 $this->set('hash', $hash); 379 return $this; 380 } 381 382 /** 383 * {@inheritdoc} 384 */ 385 public function setEtag($etag) { 386 $this->set('etag', $etag); 387 return $this; 388 } 389 390 /** 391 * {@inheritdoc} 392 */ 393 public function setLastModified($modified) { 394 $this->set('modified', $modified); 395 return $this; 396 } 397 398} 399