diff --git a/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php b/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php index 5b538c8..dfb5f0d 100644 --- a/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php +++ b/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php @@ -290,7 +290,9 @@ protected function invokeHook($hook, EntityInterface $entity) { protected function mapToStorageRecord(EntityInterface $entity) { $record = new \stdClass(); foreach ($this->entityInfo['schema_fields_sql']['base_table'] as $name) { - $record->$name = $entity->$name->value; + if (isset($entity->$name->value)) { + $record->$name = $entity->$name->value; + } } return $record; } diff --git a/core/lib/Drupal/Core/Entity/Field/Type/UriItem.php b/core/lib/Drupal/Core/Entity/Field/Type/UriItem.php new file mode 100644 index 0000000..7530499 --- /dev/null +++ b/core/lib/Drupal/Core/Entity/Field/Type/UriItem.php @@ -0,0 +1,39 @@ + 'string', + 'label' => t('Text value'), + ); + } + return self::$propertyDefinitions; + } +} diff --git a/core/modules/aggregator/aggregator.admin.inc b/core/modules/aggregator/aggregator.admin.inc index 3612e0c..ccf7f57 100644 --- a/core/modules/aggregator/aggregator.admin.inc +++ b/core/modules/aggregator/aggregator.admin.inc @@ -7,6 +7,7 @@ use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Drupal\aggregator\Plugin\FetcherManager; +use Drupal\aggregator\Plugin\Core\Entity\Feed; /** * Page callback: Displays the aggregator administration page. @@ -92,160 +93,35 @@ function aggregator_view() { } /** - * Form constructor for adding and editing feed sources. + * Page callback: Presents the aggregator feed creation form. * - * @param $feed - * (optional) If editing a feed, the feed to edit as a PHP stdClass value; if - * adding a new feed, NULL. Defaults to NULL. + * @return array + * A form array as expected by drupal_render(). * - * @ingroup forms * @see aggregator_menu() - * @see aggregator_form_feed_validate() - * @see aggregator_form_feed_submit() */ -function aggregator_form_feed($form, &$form_state, stdClass $feed = NULL) { - $period = drupal_map_assoc(array(900, 1800, 3600, 7200, 10800, 21600, 32400, 43200, 64800, 86400, 172800, 259200, 604800, 1209600, 2419200), 'format_interval'); - $period[AGGREGATOR_CLEAR_NEVER] = t('Never'); - - $form['title'] = array('#type' => 'textfield', - '#title' => t('Title'), - '#default_value' => isset($feed->title) ? $feed->title : '', - '#maxlength' => 255, - '#description' => t('The name of the feed (or the name of the website providing the feed).'), - '#required' => TRUE, - ); - $form['url'] = array( - '#type' => 'url', - '#title' => t('URL'), - '#default_value' => isset($feed->url) ? $feed->url : '', - '#maxlength' => NULL, - '#description' => t('The fully-qualified URL of the feed.'), - '#required' => TRUE, - ); - $form['refresh'] = array('#type' => 'select', - '#title' => t('Update interval'), - '#default_value' => isset($feed->refresh) ? $feed->refresh : 3600, - '#options' => $period, - '#description' => t('The length of time between feed updates. Requires a correctly configured cron maintenance task.', array('@cron' => url('admin/reports/status'))), - ); - $form['block'] = array('#type' => 'select', - '#title' => t('News items in block'), - '#default_value' => isset($feed->block) ? $feed->block : 5, - '#options' => drupal_map_assoc(array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20)), - '#description' => t("Drupal can make a block with the most recent news items of this feed. You can configure blocks to be displayed in the sidebar of your page. This setting lets you configure the number of news items to show in this feed's block. If you choose '0' this feed's block will be disabled.", array('@block-admin' => url('admin/structure/block'))), - ); - - // Handling of categories. - $options = array(); - $values = array(); - $categories = db_query('SELECT c.cid, c.title, f.fid FROM {aggregator_category} c LEFT JOIN {aggregator_category_feed} f ON c.cid = f.cid AND f.fid = :fid ORDER BY title', array(':fid' => isset($feed->fid) ? $feed->fid : NULL)); - foreach ($categories as $category) { - $options[$category->cid] = check_plain($category->title); - if ($category->fid) $values[] = $category->cid; - } - - if ($options) { - $form['category'] = array( - '#type' => 'checkboxes', - '#title' => t('Categorize news items'), - '#default_value' => $values, - '#options' => $options, - '#description' => t('New feed items are automatically filed in the checked categories.'), - ); - } - - $form['actions'] = array('#type' => 'actions'); - $form['actions']['submit'] = array( - '#type' => 'submit', - '#value' => t('Save'), - ); - if (!empty($feed->fid)) { - $form['actions']['delete'] = array( - '#type' => 'submit', - '#value' => t('Delete'), - ); - $form['fid'] = array( - '#type' => 'hidden', - '#value' => $feed->fid, - ); - } - - return $form; +function aggregator_feed_add() { + $feed = entity_create('aggregator_feed', array( + 'refresh' => 3600, + 'block' => 5, + )); + return entity_get_form($feed); } /** - * Form validation handler for aggregator_form_feed(). + * Page callback: Presents the aggregator feed edit form. * - * @see aggregator_form_feed_submit() - */ -function aggregator_form_feed_validate($form, &$form_state) { - if ($form_state['values']['op'] == t('Save')) { - // Check for duplicate titles. - if (isset($form_state['values']['fid'])) { - $result = db_query("SELECT title, url FROM {aggregator_feed} WHERE (title = :title OR url = :url) AND fid <> :fid", array(':title' => $form_state['values']['title'], ':url' => $form_state['values']['url'], ':fid' => $form_state['values']['fid'])); - } - else { - $result = db_query("SELECT title, url FROM {aggregator_feed} WHERE title = :title OR url = :url", array(':title' => $form_state['values']['title'], ':url' => $form_state['values']['url'])); - } - foreach ($result as $feed) { - if (strcasecmp($feed->title, $form_state['values']['title']) == 0) { - form_set_error('title', t('A feed named %feed already exists. Enter a unique title.', array('%feed' => $form_state['values']['title']))); - } - if (strcasecmp($feed->url, $form_state['values']['url']) == 0) { - form_set_error('url', t('A feed with this URL %url already exists. Enter a unique URL.', array('%url' => $form_state['values']['url']))); - } - } - } -} - -/** - * Form submission handler for aggregator_form_feed(). + * @param Drupal\aggregator\Plugin\Core\Entity\Feed $feed + * The aggregator feed to edit. * - * @see aggregator_form_feed_validate() + * @return array + * A form array as expected by drupal_render(). * - * @todo Add delete confirmation dialog. + * @see aggregator_menu() */ -function aggregator_form_feed_submit($form, &$form_state) { - // @todo Replicate this cache invalidation when these ops are separated. - // Invalidate the block cache to update aggregator feed-based derivatives. - if (module_exists('block')) { - drupal_container()->get('plugin.manager.block')->clearCachedDefinitions(); - } - if ($form_state['values']['op'] == t('Delete')) { - $title = $form_state['values']['title']; - // Unset the title. - unset($form_state['values']['title']); - } - aggregator_save_feed($form_state['values']); - if (isset($form_state['values']['fid'])) { - if (isset($form_state['values']['title'])) { - drupal_set_message(t('The feed %feed has been updated.', array('%feed' => $form_state['values']['title']))); - if (arg(0) == 'admin') { - $form_state['redirect'] = 'admin/config/services/aggregator/'; - return; - } - else { - $form_state['redirect'] = 'aggregator/sources/' . $form_state['values']['fid']; - return; - } - } - else { - watchdog('aggregator', 'Feed %feed deleted.', array('%feed' => $title)); - drupal_set_message(t('The feed %feed has been deleted.', array('%feed' => $title))); - if (arg(0) == 'admin') { - $form_state['redirect'] = 'admin/config/services/aggregator/'; - return; - } - else { - $form_state['redirect'] = 'aggregator/sources/'; - return; - } - } - } - else { - watchdog('aggregator', 'Feed %feed added.', array('%feed' => $form_state['values']['title']), WATCHDOG_NOTICE, l(t('view'), 'admin/config/services/aggregator')); - drupal_set_message(t('The feed %feed has been added.', array('%feed' => $form_state['values']['title']))); - } +function aggregator_feed_edit(Feed $feed) { + drupal_set_title(t('Edit %label feed', array('%label' => $feed->label())), PASS_THROUGH); + return entity_get_form($feed); } /** @@ -590,7 +466,7 @@ function aggregator_admin_form_submit($form, &$form_state) { * Form constructor to add/edit/delete aggregator categories. * * @param $edit - * An associative array containing: + * An object containing: * - title: A string to use for the category title. * - description: A string to use for the category description. * - cid: The category ID. @@ -600,22 +476,22 @@ function aggregator_admin_form_submit($form, &$form_state) { * @see aggregator_form_category_validate() * @see aggregator_form_category_submit() */ -function aggregator_form_category($form, &$form_state, $edit = array('title' => '', 'description' => '', 'cid' => NULL)) { +function aggregator_form_category($form, &$form_state, $edit = NULL) { $form['title'] = array('#type' => 'textfield', '#title' => t('Title'), - '#default_value' => $edit['title'], + '#default_value' => isset($edit->title) ? $edit->title : '', '#maxlength' => 64, '#required' => TRUE, ); $form['description'] = array('#type' => 'textarea', '#title' => t('Description'), - '#default_value' => $edit['description'], + '#default_value' => isset($edit->description) ? $edit->description : '', ); $form['actions'] = array('#type' => 'actions'); $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save')); - if ($edit['cid']) { + if (!empty($edit->cid)) { $form['actions']['delete'] = array('#type' => 'submit', '#value' => t('Delete')); - $form['cid'] = array('#type' => 'hidden', '#value' => $edit['cid']); + $form['cid'] = array('#type' => 'hidden', '#value' => $edit->cid); } return $form; diff --git a/core/modules/aggregator/aggregator.module b/core/modules/aggregator/aggregator.module index 35cdc19..4112470 100644 --- a/core/modules/aggregator/aggregator.module +++ b/core/modules/aggregator/aggregator.module @@ -51,11 +51,6 @@ function aggregator_help($path, $arg) { */ function aggregator_theme() { return array( - 'aggregator_wrapper' => array( - 'variables' => array('content' => NULL), - 'file' => 'aggregator.pages.inc', - 'template' => 'aggregator-wrapper', - ), 'aggregator_categorize_items' => array( 'render element' => 'form', 'file' => 'aggregator.pages.inc', @@ -74,11 +69,11 @@ function aggregator_theme() { 'template' => 'aggregator-summary-items', ), 'aggregator_summary_item' => array( - 'variables' => array('item' => NULL), + 'variables' => array('aggregator_item' => NULL, 'view_mode' => NULL), 'file' => 'aggregator.pages.inc', ), 'aggregator_item' => array( - 'variables' => array('item' => NULL), + 'variables' => array('aggregator_item' => NULL, 'view_mode' => NULL), 'file' => 'aggregator.pages.inc', 'template' => 'aggregator-item', ), @@ -107,8 +102,7 @@ function aggregator_menu() { ); $items['admin/config/services/aggregator/add/feed'] = array( 'title' => 'Add feed', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('aggregator_form_feed'), + 'page callback' => 'aggregator_feed_add', 'access arguments' => array('administer news feeds'), 'type' => MENU_LOCAL_ACTION, 'file' => 'aggregator.admin.inc', @@ -241,8 +235,8 @@ function aggregator_menu() { ); $items['aggregator/sources/%aggregator_feed/configure'] = array( 'title' => 'Configure', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('aggregator_form_feed', 2), + 'page callback' => 'aggregator_feed_edit', + 'page arguments' => array(2), 'access arguments' => array('administer news feeds'), 'type' => MENU_LOCAL_TASK, 'weight' => 1, @@ -250,8 +244,8 @@ function aggregator_menu() { ); $items['admin/config/services/aggregator/edit/feed/%aggregator_feed'] = array( 'title' => 'Edit feed', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('aggregator_form_feed', 6), + 'page callback' => 'aggregator_feed_edit', + 'page arguments' => array(6), 'access arguments' => array('administer news feeds'), 'file' => 'aggregator.admin.inc', ); @@ -276,7 +270,7 @@ function aggregator_menu() { * A string with the aggregator category title. */ function _aggregator_category_title($category) { - return $category['title']; + return $category->title; } /** @@ -399,88 +393,6 @@ function aggregator_save_category($edit) { } /** - * Adds/edits/deletes an aggregator feed. - * - * @param $edit - * An associative array describing the feed to be added/edited/deleted. - * - * @return - * The ID of the feed. - */ -function aggregator_save_feed($edit) { - if (!empty($edit['fid'])) { - // An existing feed is being modified, delete the category listings. - db_delete('aggregator_category_feed') - ->condition('fid', $edit['fid']) - ->execute(); - } - if (!empty($edit['fid']) && !empty($edit['title'])) { - db_update('aggregator_feed') - ->condition('fid', $edit['fid']) - ->fields(array( - 'title' => $edit['title'], - 'url' => $edit['url'], - 'refresh' => $edit['refresh'], - 'block' => $edit['block'], - )) - ->execute(); - } - elseif (!empty($edit['fid'])) { - $iids = db_query('SELECT iid FROM {aggregator_item} WHERE fid = :fid', array(':fid' => $edit['fid']))->fetchCol(); - if ($iids) { - db_delete('aggregator_category_item') - ->condition('iid', $iids, 'IN') - ->execute(); - } - db_delete('aggregator_feed')-> - condition('fid', $edit['fid']) - ->execute(); - db_delete('aggregator_item') - ->condition('fid', $edit['fid']) - ->execute(); - // Make sure there is no active block for this feed. - $block_configs = config_get_storage_names_with_prefix('plugin.core.block'); - foreach ($block_configs as $config_id) { - $config = config($config_id); - if ($config->get('id') == 'aggregator_feed_block:' . $edit['fid']) { - $config->delete(); - } - } - } - elseif (!empty($edit['title'])) { - $edit['fid'] = db_insert('aggregator_feed') - ->fields(array( - 'title' => $edit['title'], - 'url' => $edit['url'], - 'refresh' => $edit['refresh'], - 'block' => $edit['block'], - 'link' => '', - 'description' => '', - 'image' => '', - )) - ->execute(); - - } - if (!empty($edit['title'])) { - // The feed is being saved, save the categories as well. - if (!empty($edit['category'])) { - foreach ($edit['category'] as $cid => $value) { - if ($value) { - db_insert('aggregator_category_feed') - ->fields(array( - 'fid' => $edit['fid'], - 'cid' => $cid, - )) - ->execute(); - } - } - } - } - - return $edit['fid']; -} - -/** * Removes all items from a feed. * * @param $feed @@ -603,19 +515,17 @@ function aggregator_refresh($feed) { /** * Loads an aggregator feed. * - * @param $fid + * @param int $fid * The feed id. + * @param bool $reset + * TRUE to reset the internal cache and load from the database; + * FALSE (default) to load from the internal cache, if set. * * @return * An object describing the feed. */ -function aggregator_feed_load($fid) { - $feeds = &drupal_static(__FUNCTION__); - if (!isset($feeds[$fid])) { - $feeds[$fid] = db_query('SELECT * FROM {aggregator_feed} WHERE fid = :fid', array(':fid' => $fid))->fetchObject(); - } - - return $feeds[$fid]; +function aggregator_feed_load($fid, $reset = FALSE) { + return entity_load('aggregator_feed', $fid, $reset); } /** @@ -630,7 +540,7 @@ function aggregator_feed_load($fid) { function aggregator_category_load($cid) { $categories = &drupal_static(__FUNCTION__); if (!isset($categories[$cid])) { - $categories[$cid] = db_query('SELECT * FROM {aggregator_category} WHERE cid = :cid', array(':cid' => $cid))->fetchAssoc(); + $categories[$cid] = db_query('SELECT * FROM {aggregator_category} WHERE cid = :cid', array(':cid' => $cid))->fetchObject(); } return $categories[$cid]; diff --git a/core/modules/aggregator/aggregator.pages.inc b/core/modules/aggregator/aggregator.pages.inc index a49a666..ec638e4 100644 --- a/core/modules/aggregator/aggregator.pages.inc +++ b/core/modules/aggregator/aggregator.pages.inc @@ -73,7 +73,7 @@ function aggregator_page_source_form($form, $form_state, $feed) { * @ingroup forms */ function aggregator_page_category($category) { - drupal_add_feed('aggregator/rss/' . $category['cid'], config('system.site')->get('name') . ' ' . t('aggregator - @title', array('@title' => $category['title']))); + drupal_add_feed('aggregator/rss/' . $category->cid, config('system.site')->get('name') . ' ' . t('aggregator - @title', array('@title' => $category->title))); // It is safe to include the cid in the query because it's loaded from the // database by aggregator_category_load(). @@ -120,20 +120,18 @@ function aggregator_page_category_form($form, $form_state, $category) { * @return * An array of the feed items. */ -function aggregator_load_feed_items($type, $data = NULL) { +function aggregator_load_feed_items($type, $data = NULL, $limit = 20) { $items = array(); switch ($type) { case 'sum': $query = db_select('aggregator_item', 'i'); $query->join('aggregator_feed', 'f', 'i.fid = f.fid'); - $query->fields('i'); - $query->addField('f', 'title', 'ftitle'); - $query->addField('f', 'link', 'flink'); + $query->fields('i', array('iid')); break; case 'source': $query = db_select('aggregator_item', 'i'); $query - ->fields('i') + ->fields('i', array('iid')) ->condition('i.fid', $data->fid); break; case 'category': @@ -141,25 +139,19 @@ function aggregator_load_feed_items($type, $data = NULL) { $query->leftJoin('aggregator_item', 'i', 'c.iid = i.iid'); $query->leftJoin('aggregator_feed', 'f', 'i.fid = f.fid'); $query - ->fields('i') - ->condition('cid', $data['cid']); - $query->addField('f', 'title', 'ftitle'); - $query->addField('f', 'link', 'flink'); + ->fields('i', array('iid')) + ->condition('cid', $data->cid); break; } $result = $query ->extend('Drupal\Core\Database\Query\PagerSelectExtender') - ->limit(20) + ->limit($limit) ->orderBy('i.timestamp', 'DESC') ->orderBy('i.iid', 'DESC') ->execute(); - foreach ($result as $item) { - $item->categories = db_query('SELECT c.title, c.cid FROM {aggregator_category_item} ci LEFT JOIN {aggregator_category} c ON ci.cid = c.cid WHERE ci.iid = :iid ORDER BY c.title', array(':iid' => $item->iid))->fetchAll(); - $items[] = $item; - } - + $items = entity_load_multiple('aggregator_item', $result->fetchCol()); return $items; } @@ -182,18 +174,24 @@ function aggregator_load_feed_items($type, $data = NULL) { function _aggregator_page_list($items, $op, $feed_source = '') { if (user_access('administer news feeds') && ($op == 'categorize')) { // Get form data. - $output = aggregator_categorize_items($items, $feed_source); + $build = aggregator_categorize_items($items, $feed_source); } else { - // Assemble themed output. - $output = $feed_source; - foreach ($items as $item) { - $output .= theme('aggregator_item', array('item' => $item)); + // Assemble output. + $build = array( + '#type' => 'container', + '#attributes' => array('class' => array('aggregator-wrapper')), + 'feed_source' => array( + '#markup' => $feed_source, + ), + ); + if ($items) { + $build['items'] = entity_view_multiple($items, 'default'); + $build['pager']['#markup'] = theme('pager'); } - $output = theme('aggregator_wrapper', array('content' => $output)); } - return $output; + return $build; } /** @@ -220,13 +218,15 @@ function aggregator_categorize_items($items, $feed_source = '') { $categories = array(); $done = FALSE; $form['items'] = array(); + if ($items) { + $form['items'] = entity_view_multiple($items, 'default'); + } $form['categories'] = array( '#tree' => TRUE, ); foreach ($items as $item) { - $form['items'][$item->iid] = array('#markup' => theme('aggregator_item', array('item' => $item))); - $form['categories'][$item->iid] = array(); - $categories_result = db_query('SELECT c.cid, c.title, ci.iid FROM {aggregator_category} c LEFT JOIN {aggregator_category_item} ci ON c.cid = ci.cid AND ci.iid = :iid', array(':iid' => $item->iid)); + $form['categories'][$item->id()] = array(); + $categories_result = db_query('SELECT c.cid, c.title, ci.iid FROM {aggregator_category} c LEFT JOIN {aggregator_category_item} ci ON c.cid = ci.cid AND ci.iid = :iid', array(':iid' => $item->id())); $selected = array(); foreach ($categories_result as $category) { if (!$done) { @@ -237,7 +237,7 @@ function aggregator_categorize_items($items, $feed_source = '') { } } $done = TRUE; - $form['categories'][$item->iid] = array( + $form['categories'][$item->id()] = array( '#type' => config('aggregator.settings')->get('source.category_selector'), '#default_value' => $selected, '#options' => $categories, @@ -305,7 +305,8 @@ function theme_aggregator_categorize_items($variables) { $output .= drupal_render($form['submit']); $output .= drupal_render_children($form); - return theme('aggregator_wrapper', array('content' => $output)); + $output .= theme('pager'); + return $output; } /** @@ -324,38 +325,28 @@ function theme_aggregator_summary_item($variables) { } /** - * Processes variables for aggregator-wrapper.tpl.php. - * - * @see aggregator-wrapper.tpl.php - */ -function template_preprocess_aggregator_wrapper(&$variables) { - drupal_add_css(drupal_get_path('module', 'aggregator') . '/aggregator.theme.css'); - $variables['pager'] = theme('pager'); -} - -/** * Processes variables for aggregator-item.tpl.php. * * @see aggregator-item.tpl.php */ function template_preprocess_aggregator_item(&$variables) { - $item = $variables['item']; + $item = $variables['aggregator_item']; - $variables['feed_url'] = check_url($item->link); - $variables['feed_title'] = check_plain($item->title); - $variables['content'] = aggregator_filter_xss($item->description); + $variables['feed_url'] = check_url($item->link->value); + $variables['feed_title'] = check_plain($item->title->value); + $variables['content'] = aggregator_filter_xss($item->description->value); $variables['source_url'] = ''; $variables['source_title'] = ''; - if (isset($item->ftitle) && isset($item->fid)) { - $variables['source_url'] = url("aggregator/sources/$item->fid"); + if (isset($item->ftitle) && isset($item->fid->value)) { + $variables['source_url'] = url("aggregator/sources/$item->fid->value"); $variables['source_title'] = check_plain($item->ftitle); } - if (date('Ymd', $item->timestamp) == date('Ymd')) { - $variables['source_date'] = t('%ago ago', array('%ago' => format_interval(REQUEST_TIME - $item->timestamp))); + if (date('Ymd', $item->timestamp->value) == date('Ymd')) { + $variables['source_date'] = t('%ago ago', array('%ago' => format_interval(REQUEST_TIME - $item->timestamp->value))); } else { - $variables['source_date'] = format_date($item->timestamp, 'medium'); + $variables['source_date'] = format_date($item->timestamp->value, 'medium'); } $variables['categories'] = array(); @@ -375,23 +366,33 @@ function template_preprocess_aggregator_item(&$variables) { function aggregator_page_sources() { $result = db_query('SELECT f.fid, f.title, f.description, f.image, MAX(i.timestamp) AS last FROM {aggregator_feed} f LEFT JOIN {aggregator_item} i ON f.fid = i.fid GROUP BY f.fid, f.title, f.description, f.image ORDER BY last DESC, f.title'); - $output = ''; + $build = array( + '#type' => 'container', + '#attributes' => array('class' => array('aggregator-wrapper')), + '#sorted' => TRUE, + ); foreach ($result as $feed) { // Most recent items: $summary_items = array(); $aggregator_summary_items = config('aggregator.settings')->get('source.list_max'); if ($aggregator_summary_items) { - $items = db_query_range('SELECT i.title, i.timestamp, i.link FROM {aggregator_item} i WHERE i.fid = :fid ORDER BY i.timestamp DESC', 0, $aggregator_summary_items, array(':fid' => $feed->fid)); - foreach ($items as $item) { - $summary_items[] = theme('aggregator_summary_item', array('item' => $item)); + if ($items = aggregator_load_feed_items('source', $feed, $aggregator_summary_items)) { + $summary_items = entity_view_multiple($items, 'summary'); } } $feed->url = url('aggregator/sources/' . $feed->fid); - $output .= theme('aggregator_summary_items', array('summary_items' => $summary_items, 'source' => $feed)); + $build[$feed->fid] = array( + '#theme' => 'aggregator_summary_items', + '#summary_items' => $summary_items, + '#source' => $feed, + ); } - $output .= theme('feed_icon', array('url' => 'aggregator/opml', 'title' => t('OPML feed'))); - - return theme('aggregator_wrapper', array('content' => $output)); + $build['feed_icon'] = array( + '#theme' => 'feed_icon', + '#url' => 'aggregator/opml', + '#title' => t('OPML feed'), + ); + return $build; } /** @@ -405,21 +406,28 @@ function aggregator_page_sources() { function aggregator_page_categories() { $result = db_query('SELECT c.cid, c.title, c.description FROM {aggregator_category} c LEFT JOIN {aggregator_category_item} ci ON c.cid = ci.cid LEFT JOIN {aggregator_item} i ON ci.iid = i.iid GROUP BY c.cid, c.title, c.description'); - $output = ''; + $build = array( + '#type' => 'container', + '#attributes' => array('class' => array('aggregator-wrapper')), + '#sorted' => TRUE, + ); + $aggregator_summary_items = config('aggregator.settings')->get('source.list_max'); foreach ($result as $category) { - $aggregator_summary_items = config('aggregator.settings')->get('source.list_max'); + $summary_items = array(); if ($aggregator_summary_items) { - $summary_items = array(); - $items = db_query_range('SELECT i.title, i.timestamp, i.link, f.title as feed_title, f.link as feed_link FROM {aggregator_category_item} ci LEFT JOIN {aggregator_item} i ON i.iid = ci.iid LEFT JOIN {aggregator_feed} f ON i.fid = f.fid WHERE ci.cid = :cid ORDER BY i.timestamp DESC', 0, $aggregator_summary_items, array(':cid' => $category->cid)); - foreach ($items as $item) { - $summary_items[] = theme('aggregator_summary_item', array('item' => $item)); + if ($items = aggregator_load_feed_items('category', $category, $aggregator_summary_items)) { + $summary_items = entity_view_multiple($items, 'summary'); } } $category->url = url('aggregator/categories/' . $category->cid); - $output .= theme('aggregator_summary_items', array('summary_items' => $summary_items, 'source' => $category)); + $build[$category->cid] = array( + '#theme' => 'aggregator_summary_items', + '#summary_items' => $summary_items, + '#source' => $category, + ); } - return theme('aggregator_wrapper', array('content' => $output)); + return $build; } /** @@ -557,7 +565,11 @@ function theme_aggregator_page_opml($variables) { */ function template_preprocess_aggregator_summary_items(&$variables) { $variables['title'] = check_plain($variables['source']->title); - $variables['summary_list'] = theme('item_list', array('items' => $variables['summary_items'])); + $rendered_items = array(); + foreach (element_children($variables['summary_items']) as $key) { + $rendered_items[] = drupal_render($variables['summary_items'][$key]); + } + $variables['summary_list'] = theme('item_list', array('items' => $rendered_items)); $variables['source_url'] = $variables['source']->url; } @@ -567,19 +579,19 @@ function template_preprocess_aggregator_summary_items(&$variables) { * @see aggregator-summary-item.tpl.php */ function template_preprocess_aggregator_summary_item(&$variables) { - $item = $variables['item']; + $item = $variables['aggregator_item']; - $variables['item_url'] = l(check_plain($item->title), check_url(url($item->link, array('absolute' => TRUE))), array( + $variables['item_url'] = l(check_plain($item->label()), check_url(url($item->link->value, array('absolute' => TRUE))), array( 'attributes' => array( 'class' => array('feed-item-url',), ), )); $variables['item_age'] = theme('datetime', array( 'attributes' => array( - 'datetime' => format_date($item->timestamp, 'html_datetime', '', 'UTC'), + 'datetime' => format_date($item->timestamp->value, 'html_datetime', '', 'UTC'), 'class' => array('feed-item-age',), ), - 'text' => t('%age old', array('%age' => format_interval(REQUEST_TIME - $item->timestamp))), + 'text' => t('%age old', array('%age' => format_interval(REQUEST_TIME - $item->timestamp->value))), 'html' => TRUE, )); } diff --git a/core/modules/aggregator/aggregator.processor.inc b/core/modules/aggregator/aggregator.processor.inc index f585a3c..b480271 100644 --- a/core/modules/aggregator/aggregator.processor.inc +++ b/core/modules/aggregator/aggregator.processor.inc @@ -22,26 +22,46 @@ function aggregator_aggregator_process($feed) { if (is_object($feed)) { if (is_array($feed->items)) { foreach ($feed->items as $item) { + // @todo: The default entity render controller 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'])) { - $entry = db_query("SELECT iid, timestamp FROM {aggregator_item} WHERE fid = :fid AND guid = :guid", array(':fid' => $feed->fid, ':guid' => $item['guid']))->fetchObject(); + $values = array('fid' => $feed->fid, 'guid' => $item['guid']); } elseif ($item['link'] && $item['link'] != $feed->link && $item['link'] != $feed->url) { - $entry = db_query("SELECT iid, timestamp FROM {aggregator_item} WHERE fid = :fid AND link = :link", array(':fid' => $feed->fid, ':link' => $item['link']))->fetchObject(); + $values = array('fid' => $feed->fid, 'link' => $item['link']); + } + else { + $values = array('fid' => $feed->fid, 'title' => $item['title']); + } + + // Try to load an existing entry. + if ($entry = entity_load_multiple_by_properties('aggregator_item', $values)) { + $entry = reset($entry); } else { - $entry = db_query("SELECT iid, timestamp FROM {aggregator_item} WHERE fid = :fid AND title = :title", array(':fid' => $feed->fid, ':title' => $item['title']))->fetchObject(); + $entry = entity_create('aggregator_item', array()); } - if (!$item['timestamp']) { - $item['timestamp'] = isset($entry->timestamp) ? $entry->timestamp : REQUEST_TIME; + if ($item['timestamp']) { + $entry->timestamp->value = $item['timestamp']; } // Make sure the item title and author fit in the 255 varchar column. - $item['title'] = truncate_utf8($item['title'], 255, TRUE, TRUE); - $item['author'] = truncate_utf8($item['author'], 255, TRUE, TRUE); - aggregator_save_item(array('iid' => (isset($entry->iid) ? $entry->iid : ''), 'fid' => $feed->fid, 'timestamp' => $item['timestamp'], 'title' => $item['title'], 'link' => $item['link'], 'author' => $item['author'], 'description' => $item['description'], 'guid' => $item['guid'])); + $entry->title->value = truncate_utf8($item['title'], 255, TRUE, TRUE); + $entry->author->value = truncate_utf8($item['author'], 255, TRUE, TRUE); + + $entry->fid->value = $feed->fid; + $entry->link->value = $item['link']; + $entry->description->value = $item['description']; + $entry->guid->value = $item['guid']; + $entry->save(); } } } @@ -52,14 +72,7 @@ function aggregator_aggregator_process($feed) { */ function aggregator_aggregator_remove($feed) { $iids = db_query('SELECT iid FROM {aggregator_item} WHERE fid = :fid', array(':fid' => $feed->fid))->fetchCol(); - if ($iids) { - db_delete('aggregator_category_item') - ->condition('iid', $iids, 'IN') - ->execute(); - } - db_delete('aggregator_item') - ->condition('fid', $feed->fid) - ->execute(); + entity_delete_multiple('aggregator_item', $iids); drupal_set_message(t('The news items from %site have been removed.', array('%site' => $feed->title))); } @@ -145,48 +158,6 @@ function _aggregator_characters($length) { } /** - * Adds/edits/deletes an aggregator item. - * - * @param $edit - * An associative array describing the item to be added/edited/deleted. - */ -function aggregator_save_item($edit) { - if ($edit['title'] && empty($edit['iid'])) { - $edit['iid'] = db_insert('aggregator_item') - ->fields(array( - 'title' => $edit['title'], - 'link' => $edit['link'], - 'author' => $edit['author'], - 'description' => $edit['description'], - 'guid' => $edit['guid'], - 'timestamp' => $edit['timestamp'], - 'fid' => $edit['fid'], - )) - ->execute(); - } - if ($edit['iid'] && !$edit['title']) { - db_delete('aggregator_item') - ->condition('iid', $edit['iid']) - ->execute(); - db_delete('aggregator_category_item') - ->condition('iid', $edit['iid']) - ->execute(); - } - elseif ($edit['title'] && $edit['link']) { - // file the items in the categories indicated by the feed - $result = db_query('SELECT cid FROM {aggregator_category_feed} WHERE fid = :fid', array(':fid' => $edit['fid'])); - foreach ($result as $category) { - db_merge('aggregator_category_item') - ->key(array( - 'iid' => $edit['iid'], - 'cid' => $category->cid, - )) - ->execute(); - } - } -} - -/** * Expires items from a feed depending on expiration settings. * * @param $feed @@ -204,12 +175,7 @@ function aggregator_expire($feed) { )) ->fetchCol(); if ($iids) { - db_delete('aggregator_category_item') - ->condition('iid', $iids, 'IN') - ->execute(); - db_delete('aggregator_item') - ->condition('iid', $iids, 'IN') - ->execute(); + entity_delete_multiple('aggregator_item', $iids); } } } diff --git a/core/modules/aggregator/lib/Drupal/aggregator/FeedFormController.php b/core/modules/aggregator/lib/Drupal/aggregator/FeedFormController.php new file mode 100644 index 0000000..b606aa1 --- /dev/null +++ b/core/modules/aggregator/lib/Drupal/aggregator/FeedFormController.php @@ -0,0 +1,138 @@ + 'textfield', + '#title' => t('Title'), + '#default_value' => $feed->label(), + '#maxlength' => 255, + '#description' => t('The name of the feed (or the name of the website providing the feed).'), + '#required' => TRUE, + ); + $form['url'] = array( + '#type' => 'url', + '#title' => t('URL'), + '#default_value' => $feed->url->value, + '#maxlength' => NULL, + '#description' => t('The fully-qualified URL of the feed.'), + '#required' => TRUE, + ); + $form['refresh'] = array('#type' => 'select', + '#title' => t('Update interval'), + '#default_value' => $feed->refresh->value, + '#options' => $period, + '#description' => t('The length of time between feed updates. Requires a correctly configured cron maintenance task.', array('@cron' => url('admin/reports/status'))), + ); + $form['block'] = array('#type' => 'select', + '#title' => t('News items in block'), + '#default_value' => $feed->block->value, + '#options' => drupal_map_assoc(array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20)), + '#description' => t("Drupal can make a block with the most recent news items of this feed. You can configure blocks to be displayed in the sidebar of your page. This setting lets you configure the number of news items to show in this feed's block. If you choose '0' this feed's block will be disabled.", array('@block-admin' => url('admin/structure/block'))), + ); + + // Handling of categories. + $options = array(); + $values = array(); + $categories = db_query('SELECT c.cid, c.title, f.fid FROM {aggregator_category} c LEFT JOIN {aggregator_category_feed} f ON c.cid = f.cid AND f.fid = :fid ORDER BY title', array(':fid' => $feed->id())); + foreach ($categories as $category) { + $options[$category->cid] = check_plain($category->title); + if ($category->fid) $values[] = $category->cid; + } + + if ($options) { + $form['category'] = array( + '#type' => 'checkboxes', + '#title' => t('Categorize news items'), + '#default_value' => $values, + '#options' => $options, + '#description' => t('New feed items are automatically filed in the checked categories.'), + ); + } + + return parent::form($form, $form_state, $feed); + } + + /** + * Overrides Drupal\Core\Entity\EntityFormController::validate(). + */ + public function validate(array $form, array &$form_state) { + $feed = $this->buildEntity($form, $form_state); + // Check for duplicate titles. + if ($feed->id()) { + $result = db_query("SELECT title, url FROM {aggregator_feed} WHERE (title = :title OR url = :url) AND fid <> :fid", array(':title' => $feed->label(), ':url' => $feed->url->value, ':fid' => $feed->id())); + } + else { + $result = db_query("SELECT title, url FROM {aggregator_feed} WHERE title = :title OR url = :url", array(':title' => $feed->label(), ':url' => $feed->url->value)); + } + + foreach ($result as $item) { + if (strcasecmp($item->title, $feed->label()) == 0) { + form_set_error('title', t('A feed named %feed already exists. Enter a unique title.', array('%feed' => $feed->label()))); + } + if (strcasecmp($item->url, $feed->url->value) == 0) { + form_set_error('url', t('A feed with this URL %url already exists. Enter a unique URL.', array('%url' => $feed->url->value))); + } + } + parent::validate($form, $form_state); + } + + /** + * Overrides Drupal\Core\Entity\EntityFormController::save(). + */ + public function save(array $form, array &$form_state) { + $feed = $this->getEntity($form_state); + $insert = (bool) $feed->id(); + $feed->save(); + if ($insert) { + drupal_set_message(t('The feed %feed has been updated.', array('%feed' => $feed->label()))); + if (arg(0) == 'admin') { + $form_state['redirect'] = 'admin/config/services/aggregator'; + } + else { + $form_state['redirect'] = 'aggregator/sources/' . $feed->id(); + } + } + else { + watchdog('aggregator', 'Feed %feed added.', array('%feed' => $feed->label()), WATCHDOG_NOTICE, l(t('view'), 'admin/config/services/aggregator')); + drupal_set_message(t('The feed %feed has been added.', array('%feed' => $feed->label()))); + } + } + + /** + * Overrides Drupal\Core\Entity\EntityFormController::delete(). + */ + public function delete(array $form, array &$form_state) { + $feed = $this->getEntity($form_state); + $feed->delete(); + watchdog('aggregator', 'Feed %feed deleted.', array('%feed' => $feed->label())); + drupal_set_message(t('The feed %feed has been deleted.', array('%feed' => $feed->label()))); + if (arg(0) == 'admin') { + $form_state['redirect'] = 'admin/config/services/aggregator'; + } + else { + $form_state['redirect'] = 'aggregator/sources'; + } + } + +} diff --git a/core/modules/aggregator/lib/Drupal/aggregator/FeedStorageController.php b/core/modules/aggregator/lib/Drupal/aggregator/FeedStorageController.php new file mode 100644 index 0000000..1f429f8 --- /dev/null +++ b/core/modules/aggregator/lib/Drupal/aggregator/FeedStorageController.php @@ -0,0 +1,183 @@ + '', + 'description' => '', + 'image' => '', + ); + return parent::create($values); + } + + /** + * Overrides Drupal\Core\Entity\DataBaseStorageController::preDelete(). + */ + protected function preDelete($entities) { + parent::preDelete($entities); + + // Invalidate the block cache to update aggregator feed-based derivatives. + if (module_exists('block')) { + drupal_container()->get('plugin.manager.block')->clearCachedDefinitions(); + } + foreach ($entities as $entity) { + $iids = db_query('SELECT iid FROM {aggregator_item} WHERE fid = :fid', array(':fid' => $entity->id()))->fetchCol(); + if ($iids) { + entity_delete_multiple('aggregator_item', $iids); + } + } + } + + /** + * Overrides Drupal\Core\Entity\DataBaseStorageController::postDelete(). + */ + protected function postDelete($entities) { + parent::postDelete($entities); + + foreach ($entities as $entity) { + // Make sure there is no active block for this feed. + $block_configs = config_get_storage_names_with_prefix('plugin.core.block'); + foreach ($block_configs as $config_id) { + $config = config($config_id); + if ($config->get('id') == 'aggregator_feed_block:' . $entity->id()) { + $config->delete(); + } + } + } + } + + /** + * Overrides Drupal\Core\Entity\DataBaseStorageController::preSave(). + */ + protected function preSave(EntityInterface $entity) { + parent::preSave($entity); + + // Invalidate the block cache to update aggregator feed-based derivatives. + if (module_exists('block')) { + drupal_container()->get('plugin.manager.block')->clearCachedDefinitions(); + } + // An existing feed is being modified, delete the category listings. + db_delete('aggregator_category_feed') + ->condition('fid', $entity->id()) + ->execute(); + } + + /** + * Overrides Drupal\Core\Entity\DataBaseStorageController::postSave(). + */ + protected function postSave(EntityInterface $entity, $update) { + parent::postSave($entity, $update); + + if (!empty($entity->category->value)) { + foreach ($entity->category->value as $cid => $value) { + if ($value) { + db_insert('aggregator_category_feed') + ->fields(array( + 'fid' => $entity->id(), + 'cid' => $cid, + )) + ->execute(); + } + } + } + } + + /** + * Implements Drupal\Core\Entity\DataBaseStorageControllerNG::baseFieldDefinitions(). + */ + public function baseFieldDefinitions() { + $fields['fid'] = array( + 'label' => t('ID'), + 'description' => t('The ID of the aggregor feed.'), + 'type' => 'integer_field', + 'read-only' => TRUE, + ); + $fields['langcode'] = array( + 'label' => t('Language code'), + 'description' => t('The language code of the aggregator feed.'), + 'type' => 'language_field', + ); + $fields['title'] = array( + 'label' => t('Title'), + 'description' => t('The title of the feed.'), + 'type' => 'string_field', + ); + $fields['url'] = array( + 'label' => t('URL'), + 'description' => t('The URL to the feed.'), + 'type' => 'uri_field', + ); + $fields['refresh'] = array( + 'label' => t('Refresh'), + 'description' => t('How often to check for new feed items, in seconds.'), + 'type' => 'integer_field', + ); + $fields['checked'] = array( + 'label' => t('Checked'), + 'description' => t('Last time feed was checked for new items, as Unix timestamp.'), + 'type' => 'integer_field', + ); + $fields['queued'] = array( + 'label' => t('Queued'), + 'description' => t('Time when this feed was queued for refresh, 0 if not queued.'), + 'type' => 'integer_field', + ); + $fields['link'] = array( + 'label' => t('Link'), + 'description' => t('The link of the feed.'), + 'type' => 'uri_field', + ); + $fields['description'] = array( + 'label' => t('Description'), + 'description' => t("The parent website's description that comes from the element in the feed."), + 'type' => 'string_field', + ); + $fields['image'] = array( + 'label' => t('image'), + 'description' => t('An image representing the feed.'), + 'type' => 'uri_field', + ); + $fields['hash'] = array( + 'label' => t('Hash'), + 'description' => t('Calculated hash of the feed data, used for validating cache.'), + 'type' => 'string_field', + ); + $fields['etag'] = array( + 'label' => t('Etag'), + 'description' => t('Entity tag HTTP response header, used for validating cache.'), + 'type' => 'string_field', + ); + $fields['modified'] = array( + 'label' => t('Modified'), + 'description' => t('When the feed was last modified, as a Unix timestamp.'), + 'type' => 'integer_field', + ); + $fields['block'] = array( + 'label' => t('Block'), + 'description' => t('Number of items to display in the feed’s block.'), + 'type' => 'integer_field', + ); + return $fields; + } + +} diff --git a/core/modules/aggregator/lib/Drupal/aggregator/ItemRenderController.php b/core/modules/aggregator/lib/Drupal/aggregator/ItemRenderController.php new file mode 100644 index 0000000..160bb72 --- /dev/null +++ b/core/modules/aggregator/lib/Drupal/aggregator/ItemRenderController.php @@ -0,0 +1,31 @@ +timestamp->value = REQUEST_TIME; + return $entity; + } + + /** + * Overrides Drupal\Core\Entity\DataBaseStorageController::attachLoad(). + */ + protected function attachLoad(&$queried_entities, $load_revision = FALSE) { + parent::attachLoad($queried_entities, $load_revision); + foreach ($queried_entities as $item) { + $item->categories = db_query('SELECT c.title, c.cid FROM {aggregator_category_item} ci LEFT JOIN {aggregator_category} c ON ci.cid = c.cid WHERE ci.iid = :iid ORDER BY c.title', array(':iid' => $item->id()))->fetchAll(); + } + } + + /** + * Overrides Drupal\Core\Entity\DataBaseStorageController::preDelete(). + */ + protected function preDelete($entities) { + parent::preDelete($entities); + + db_delete('aggregator_category_item') + ->condition('iid', array_keys($entities), 'IN') + ->execute(); + } + + /** + * Overrides Drupal\Core\Entity\DataBaseStorageController::postSave(). + */ + protected function postSave(EntityInterface $entity, $update) { + parent::postSave($entity, $update); + + $result = db_query('SELECT cid FROM {aggregator_category_feed} WHERE fid = :fid', array(':fid' => $entity->fid->value)); + foreach ($result as $category) { + db_merge('aggregator_category_item') + ->key(array( + 'iid' => $entity->id(), + 'cid' => $category->cid, + )) + ->execute(); + } + } + + /** + * Implements Drupal\Core\Entity\DataBaseStorageControllerNG::baseFieldDefinitions(). + */ + public function baseFieldDefinitions() { + $fields['iid'] = array( + 'label' => t('ID'), + 'description' => t('The ID of the aggregor item.'), + 'type' => 'integer_field', + 'read-only' => TRUE, + ); + $fields['fid'] = array( + 'label' => t('Aggregator feed ID'), + 'description' => t('The ID of the aggregator feed.'), + 'type' => 'integer_field', + ); + $fields['title'] = array( + 'label' => t('Title'), + 'description' => t('The title of the feed item.'), + 'type' => 'string_field', + ); + $fields['link'] = array( + 'label' => t('Link'), + 'description' => t('The link of the feed item.'), + 'type' => 'uri_field', + ); + $fields['author'] = array( + 'label' => t('Author'), + 'description' => t('The author of the feed item.'), + 'type' => 'string_field', + ); + $fields['description'] = array( + 'label' => t('Description'), + 'description' => t('The body of the feed item.'), + 'type' => 'string_field', + ); + $fields['timestamp'] = array( + 'label' => t('Posted timestamp'), + 'description' => t('Posted date of the feed item, as a Unix timestamp.'), + 'type' => 'integer_field', + ); + $fields['guid'] = array( + 'label' => t('GUID'), + 'description' => t('Unique identifier for the feed item.'), + 'type' => 'string_field', + ); + return $fields; + } + +} diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/Core/Entity/Feed.php b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/Core/Entity/Feed.php new file mode 100644 index 0000000..d859d94 --- /dev/null +++ b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/Core/Entity/Feed.php @@ -0,0 +1,182 @@ + element in the feed. + * + * @var \Drupal\Core\Entity\Field\FieldInterface + */ + public $link ; + + /** + * The parent website's description; + * comes from the element in the feed. + * + * @var \Drupal\Core\Entity\Field\FieldInterface + */ + public $description; + + /** + * An image representing the feed. + * + * @var \Drupal\Core\Entity\Field\FieldInterface + */ + public $image; + + /** + * Calculated hash of the feed data, used for validating cache. + * + * @var \Drupal\Core\Entity\Field\FieldInterface + */ + public $hash; + + /** + * Entity tag HTTP response header, used for validating cache. + * + * @var \Drupal\Core\Entity\Field\FieldInterface + */ + public $etag; + + /** + * When the feed was last modified, as a Unix timestamp. + * + * @var \Drupal\Core\Entity\Field\FieldInterface + */ + public $modified; + + /** + * Number of items to display in the feed’s block. + * + * @var \Drupal\Core\Entity\Field\FieldInterface + */ + public $block; + + /** + * Implements Drupal\Core\Entity\EntityInterface::__construct(). + */ + public function __construct(array $values, $entity_type) { + parent::__construct($values, $entity_type); + + // We unset all defined properties, so magic getters apply. + unset($this->fid); + unset($this->title); + unset($this->url); + unset($this->refresh); + unset($this->checked); + unset($this->queued); + unset($this->link); + unset($this->description); + unset($this->image); + unset($this->hash); + unset($this->etag); + unset($this->modified); + unset($this->block); + + } + + /** + * Implements Drupal\Core\Entity\EntityInterface::id(). + */ + public function id() { + return $this->get('fid')->value; + } + + /** + * Implements Drupal\Core\Entity\EntityInterface::label(). + */ + public function label($langcode = NULL) { + return $this->get('title')->value; + } +} diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/Core/Entity/Item.php b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/Core/Entity/Item.php new file mode 100644 index 0000000..0875d10 --- /dev/null +++ b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/Core/Entity/Item.php @@ -0,0 +1,124 @@ +iid); + unset($this->fid); + unset($this->title); + unset($this->author); + unset($this->description); + unset($this->guid); + unset($this->link); + unset($this->timestamp); + } + + /** + * Implements Drupal\Core\Entity\EntityInterface::id(). + */ + public function id() { + return $this->get('iid')->value; + } + + /** + * Implements Drupal\Core\Entity\EntityInterface::label(). + */ + public function label($langcode = NULL) { + return $this->get('title')->value; + } +} diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Tests/AddFeedTest.php b/core/modules/aggregator/lib/Drupal/aggregator/Tests/AddFeedTest.php index 9f6fc24..49c3a22 100644 --- a/core/modules/aggregator/lib/Drupal/aggregator/Tests/AddFeedTest.php +++ b/core/modules/aggregator/lib/Drupal/aggregator/Tests/AddFeedTest.php @@ -35,6 +35,7 @@ function testAddFeed() { $this->assertText($feed->title, 'Page title'); $this->drupalGet('aggregator/sources/' . $feed->fid . '/categorize'); $this->assertResponse(200, 'Feed categorization page exists.'); + $this->assertText($feed->title); // Delete feed. $this->deleteFeed($feed); @@ -63,6 +64,7 @@ function testAddLongFeed() { $this->assertText($feed->title, 'Page title'); $this->drupalGet('aggregator/sources/' . $feed->fid . '/categorize'); $this->assertResponse(200, 'Long URL feed categorization page exists.'); + $this->assertText($feed->title); // Delete feeds. $this->deleteFeed($feed); diff --git a/core/modules/aggregator/templates/aggregator-wrapper.tpl.php b/core/modules/aggregator/templates/aggregator-wrapper.tpl.php deleted file mode 100644 index 0e97ba4..0000000 --- a/core/modules/aggregator/templates/aggregator-wrapper.tpl.php +++ /dev/null @@ -1,20 +0,0 @@ - -
- - -
diff --git a/core/modules/system/system.module b/core/modules/system/system.module index 6d16229..966e4cf 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -2245,6 +2245,12 @@ function system_data_type_info() { 'class' => '\Drupal\Core\Entity\Field\Type\EntityReferenceItem', 'list class' => '\Drupal\Core\Entity\Field\Type\Field', ), + 'uri_field' => array( + 'label' => t('URI field item'), + 'description' => t('An entity field containing a URI'), + 'class' => '\Drupal\Core\Entity\Field\Type\UriItem', + 'list class' => '\Drupal\Core\Entity\Field\Type\Field', + ), ); }