Issue #2127725 by ParisLiakos: Remove category handling from aggregator.

8.0.x
webchick 2013-12-06 15:32:13 -08:00
parent 8bacdc2aa6
commit 2e8b1a44ca
44 changed files with 18 additions and 2340 deletions

View File

@ -27,97 +27,6 @@ function aggregator_requirements($phase) {
* Implements hook_schema().
*/
function aggregator_schema() {
$schema['aggregator_category'] = array(
'description' => 'Stores categories for aggregator feeds and feed items.',
'fields' => array(
'cid' => array(
'type' => 'serial',
'not null' => TRUE,
'description' => 'Primary Key: Unique aggregator category ID.',
),
'title' => array(
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
'description' => 'Title of the category.',
),
'description' => array(
'type' => 'text',
'not null' => TRUE,
'size' => 'big',
'description' => 'Description of the category',
),
'block' => array(
'type' => 'int',
'not null' => TRUE,
'default' => 0,
'size' => 'tiny',
'description' => 'The number of recent items to show within the category block.',
)
),
'primary key' => array('cid'),
'unique keys' => array(
'title' => array('title'),
),
);
$schema['aggregator_category_feed'] = array(
'description' => 'Bridge table; maps feeds to categories.',
'fields' => array(
'fid' => array(
'type' => 'int',
'not null' => TRUE,
'default' => 0,
'description' => "The feed's {aggregator_feed}.fid.",
),
'cid' => array(
'type' => 'int',
'not null' => TRUE,
'default' => 0,
'description' => 'The {aggregator_category}.cid to which the feed is being assigned.',
)
),
'primary key' => array('cid', 'fid'),
'indexes' => array(
'fid' => array('fid'),
),
'foreign keys' => array(
'aggregator_category' => array(
'table' => 'aggregator_category',
'columns' => array('cid' => 'cid'),
),
),
);
$schema['aggregator_category_item'] = array(
'description' => 'Bridge table; maps feed items to categories.',
'fields' => array(
'iid' => array(
'type' => 'int',
'not null' => TRUE,
'default' => 0,
'description' => "The feed item's {aggregator_item}.iid.",
),
'cid' => array(
'type' => 'int',
'not null' => TRUE,
'default' => 0,
'description' => 'The {aggregator_category}.cid to which the feed item is being assigned.',
)
),
'primary key' => array('cid', 'iid'),
'indexes' => array(
'iid' => array('iid'),
),
'foreign keys' => array(
'aggregator_category' => array(
'table' => 'aggregator_category',
'columns' => array('cid' => 'cid'),
),
),
);
$schema['aggregator_feed'] = array(
'description' => 'Stores feeds to be parsed by the aggregator.',
'fields' => array(
@ -297,7 +206,6 @@ function aggregator_update_8000() {
'aggregator_teaser_length' => 'items.teaser_length',
'aggregator_clear' => 'items.expire',
'aggregator_summary_items' => 'source.list_max',
'aggregator_category_selector' => 'source.category_selector',
));
}

View File

@ -4,12 +4,6 @@ aggregator.feed_add:
appears_on:
- 'aggregator.admin_overview'
aggregator.category_add:
route_name: aggregator.category_add
title: 'Add category'
appears_on:
- 'aggregator.admin_overview'
aggregator.opml_add:
route_name: aggregator.opml_add
title: 'Import OPML'

View File

@ -8,28 +8,10 @@ aggregator.admin_settings:
weight: 100
tab_root_id: aggregator.admin_overview
aggregator.category_view:
route_name: aggregator.category_view
tab_root_id: aggregator.category_view
title: 'View'
aggregator.categorize_category_form:
route_name: aggregator.categorize_category_form
tab_root_id: aggregator.category_view
title: Categorize
aggregator.category_edit:
route_name: aggregator.category_edit
tab_root_id: aggregator.category_view
title: Configure
weight: 10
aggregator.feed_view:
route_name: aggregator.feed_view
tab_root_id: aggregator.feed_view
title: View
aggregator.categorize_feed_form:
route_name: aggregator.categorize_feed_form
tab_root_id: aggregator.feed_view
title: 'Categorize'
aggregator.feed_configure:
route_name: aggregator.feed_configure
tab_root_id: aggregator.feed_view

View File

@ -25,7 +25,7 @@ function aggregator_help($path, $arg) {
$output .= '<h3>' . t('Uses') . '</h3>';
$output .= '<dl>';
$output .= '<dt>' . t('Viewing feeds') . '</dt>';
$output .= '<dd>' . t('Feeds contain published content, and may be grouped in categories, generally by topic. Users view feed content in the <a href="@aggregator">main aggregator display</a>, or by <a href="@aggregator-sources">their source</a> (usually via an RSS feed reader). The most recent content in a feed or category can be displayed as a block through the <a href="@admin-block">Blocks administration page</a>.', array('@aggregator' => url('aggregator'), '@aggregator-sources' => url('aggregator/sources'), '@admin-block' => url('admin/structure/block'))) . '</a></dd>';
$output .= '<dd>' . t('Feeds contain published content. Users view feed content in the <a href="@aggregator">main aggregator display</a>, or by <a href="@aggregator-sources">their source</a> (usually via an RSS feed reader). The most recent content in a feed can be displayed as a block through the <a href="@admin-block">Blocks administration page</a>.', array('@aggregator' => url('aggregator'), '@aggregator-sources' => url('aggregator/sources'), '@admin-block' => url('admin/structure/block'))) . '</a></dd>';
$output .= '<dt>' . t('Adding, editing, and deleting feeds') . '</dt>';
$output .= '<dd>' . t('Administrators can add, edit, and delete feeds, and choose how often to check each feed for newly updated items on the <a href="@feededit">Feed aggregator administration page</a>.', array('@feededit' => url('admin/config/services/aggregator'))) . '</dd>';
$output .= '<dt>' . t('OPML integration') . '</dt>';
@ -36,12 +36,10 @@ function aggregator_help($path, $arg) {
return $output;
case 'admin/config/services/aggregator':
$output = '<p>' . t('Thousands of sites (particularly news sites and blogs) publish their latest headlines and posts in feeds, using a number of standardized XML-based formats. Formats supported by the aggregator include <a href="@rss">RSS</a>, <a href="@rdf">RDF</a>, and <a href="@atom">Atom</a>.', array('@rss' => 'http://cyber.law.harvard.edu/rss/', '@rdf' => 'http://www.w3.org/RDF/', '@atom' => 'http://www.atomenabled.org')) . '</p>';
$output .= '<p>' . t('Current feeds are listed below, and <a href="@addfeed">new feeds may be added</a>. For each feed or feed category, the <em>latest items</em> block may be enabled at the <a href="@block">blocks administration page</a>.', array('@addfeed' => url('admin/config/services/aggregator/add/feed'), '@block' => url('admin/structure/block'))) . '</p>';
$output .= '<p>' . t('Current feeds are listed below, and <a href="@addfeed">new feeds may be added</a>. For each feed, the <em>latest items</em> block may be enabled at the <a href="@block">blocks administration page</a>.', array('@addfeed' => url('admin/config/services/aggregator/add/feed'), '@block' => url('admin/structure/block'))) . '</p>';
return $output;
case 'admin/config/services/aggregator/add/feed':
return '<p>' . t('Add a feed in RSS, RDF or Atom format. A feed may only have one entry.') . '</p>';
case 'admin/config/services/aggregator/add/category':
return '<p>' . t('Categories allow feed items from different feeds to be grouped together. For example, several sport-related feeds may belong to a category named <em>Sports</em>. Feed items may be grouped automatically (by selecting a category when creating or editing a feed) or manually (via the <em>Categorize</em> page available from feed item listings). Each category provides its own feed page and block.') . '</p>';
case 'admin/config/services/aggregator/add/opml':
return '<p>' . t('<acronym title="Outline Processor Markup Language">OPML</acronym> is an XML format used to exchange multiple feeds between aggregators. A single OPML document may contain a collection of many feeds. Drupal can parse such a file and import all feeds at once, saving you the effort of adding them manually. You may either upload a local file from your computer or enter a URL where Drupal can download it.') . '</p>';
}
@ -81,7 +79,7 @@ function aggregator_theme() {
'file' => 'aggregator.pages.inc',
),
'aggregator_page_rss' => array(
'variables' => array('feeds' => NULL, 'category' => NULL),
'variables' => array('feeds' => NULL),
'file' => 'aggregator.pages.inc',
),
);
@ -93,7 +91,7 @@ function aggregator_theme() {
function aggregator_menu() {
$items['admin/config/services/aggregator'] = array(
'title' => 'Feed aggregator',
'description' => "Configure which content your site aggregates from other sites, how often it polls them, and how they're categorized.",
'description' => "Configure which content your site aggregates from other sites, and how often it polls them.",
'route_name' => 'aggregator.admin_overview',
'weight' => 10,
);
@ -114,13 +112,6 @@ function aggregator_menu() {
'title' => 'Sources',
'route_name' => 'aggregator.sources',
);
$items['aggregator/categories'] = array(
'title' => 'Categories',
'route_name' => 'aggregator.categories',
);
$items['aggregator/categories/%aggregator_category'] = array(
'route_name' => 'aggregator.category_view',
);
$items['aggregator/sources/%aggregator_feed'] = array(
'route_name' => 'aggregator.feed_view',
);
@ -132,14 +123,6 @@ function aggregator_menu() {
'title' => 'Delete feed',
'route_name' => 'aggregator.feed_delete',
);
$items['admin/config/services/aggregator/edit/category/%aggregator_category'] = array(
'title' => 'Edit category',
'route_name' => 'aggregator.category_admin_edit',
);
$items['admin/config/services/aggregator/delete/category/%aggregator_category'] = array(
'title' => 'Delete category',
'route_name' => 'aggregator.category_delete',
);
return $items;
}
@ -199,56 +182,6 @@ function aggregator_queue_info() {
return $queues;
}
/**
* Adds/edits/deletes aggregator categories.
*
* @param $edit
* An associative array describing the category to be added/edited/deleted.
*/
function aggregator_save_category($edit) {
$link_path = 'aggregator/categories/';
if (!empty($edit['cid'])) {
$link_path .= $edit['cid'];
if (!empty($edit['title'])) {
db_merge('aggregator_category')
->key(array('cid' => $edit['cid']))
->fields(array(
'title' => $edit['title'],
'description' => $edit['description'],
))
->execute();
$op = 'update';
}
else {
db_delete('aggregator_category')
->condition('cid', $edit['cid'])
->execute();
// Make sure there is no active block for this category.
if (\Drupal::moduleHandler()->moduleExists('block')) {
foreach (entity_load_multiple_by_properties('block', array('plugin' => 'aggregator_category_block:' . $edit['cid'])) as $block) {
$block->delete();
}
}
$edit['title'] = '';
$op = 'delete';
}
}
elseif (!empty($edit['title'])) {
// A single unique id for bundles and feeds, to use in blocks.
$link_path .= db_insert('aggregator_category')
->fields(array(
'title' => $edit['title'],
'description' => $edit['description'],
'block' => 5,
))
->execute();
$op = 'insert';
}
if (isset($op) && \Drupal::moduleHandler()->moduleExists('menu_link')) {
menu_link_maintain('aggregator', $op, $link_path, $edit['title']);
}
}
/**
* Checks a news feed for new items.
*
@ -348,22 +281,6 @@ function aggregator_feed_load($fid) {
return entity_load('aggregator_feed', $fid);
}
/**
* Loads an aggregator category.
*
* @param $cid
* The category id.
*
* @return stdClass|null
* An object containing all category properties.
*
* @deprecated Use Drupal\aggregator\CategoryStorageControllerInterface::load()
* instead.
*/
function aggregator_category_load($cid) {
return \Drupal::service('aggregator.category.storage')->load($cid);
}
/**
* Prepares variables for individual feed item block templates.
*

View File

@ -16,22 +16,16 @@ use Drupal\Core\Entity\EntityInterface;
* - sum: No filtering.
* - source: Filter the feed items, limiting the result to items from a
* single source.
* - category: Filter the feed items by category.
* @param mixed $data
* Feed or category data used for filtering. The type and value of $data
* depends on $type:
* Feed data used for filtering. The type and value of $data depends on $type:
* - source: $data is an object with $data->fid identifying the feed used to
* as filter.
* - category: $data is an array with $data['cid'] being the category id to
* filter on.
* The $data parameter is not used when $type is 'sum'.
* @param int $limit
* (optional) The number of records to return. Defaults to 20.
*
* @deprecated Use \Drupal\aggregator\ItemStorageController::loadAll() for
* loading all feed items, \Drupal\aggregator\ItemStorageController::loadByFeed()
* for loading feed items filtered by the source feed, and \Drupal\aggregator\ItemStorageController::loadByCategory()
* for loading feed items filtered by the feed category.
*
* @return \Drupal\aggregator\ItemInterface[]
* An array of the feed items.
@ -44,9 +38,6 @@ function aggregator_load_feed_items($type, $data = NULL, $limit = 20) {
case 'source':
return $storage_controller->loadByFeed($data->id(), $limit);
case 'category':
return $storage_controller->loadByCategory($data->cid, $limit);
}
}
@ -81,11 +72,6 @@ function template_preprocess_aggregator_item(&$variables) {
$variables['source_date'] = format_date($item->getPostedTime(), 'medium');
}
$variables['categories'] = array();
foreach ($item->categories as $category) {
$variables['categories'][$category->cid] = l($category->title, 'aggregator/categories/' . $category->cid);
}
$variables['attributes']['class'][] = 'feed-item';
}

View File

@ -95,69 +95,6 @@ aggregator.sources:
requirements:
_permission: 'access news feeds'
aggregator.categories:
path: '/aggregator/categories'
defaults:
_content: '\Drupal\aggregator\Controller\AggregatorController::categories'
_title: 'Categories'
requirements:
_access_aggregator_categories: 'TRUE'
aggregator.category_view:
path: '/aggregator/categories/{cid}'
defaults:
_content: '\Drupal\aggregator\Controller\AggregatorController::viewCategory'
_title_callback: '\Drupal\aggregator\Controller\AggregatorController::categoryTitle'
requirements:
_permission: 'access news feeds'
aggregator.category_edit:
path: '/aggregator/categories/{cid}/configure'
defaults:
_form: '\Drupal\aggregator\Form\CategoryAdminForm'
_title: 'Configure'
requirements:
_permission: 'administer news feeds'
aggregator.category_admin_edit:
path: '/admin/config/services/aggregator/edit/category/{cid}'
defaults:
_form: '\Drupal\aggregator\Form\CategoryAdminForm'
requirements:
_permission: 'administer news feeds'
aggregator.category_delete:
path: '/admin/config/services/aggregator/delete/category/{cid}'
defaults:
_form: '\Drupal\aggregator\Form\CategoryDeleteForm'
_title: 'Delete category'
requirements:
_permission: 'administer news feeds'
aggregator.category_add:
path: '/admin/config/services/aggregator/add/category'
defaults:
_form: '\Drupal\aggregator\Form\CategoryAdminForm'
_title: 'Add category'
requirements:
_permission: 'administer news feeds'
aggregator.categorize_category_form:
path: '/aggregator/categories/{cid}/categorize'
defaults:
_form: '\Drupal\aggregator\Form\CategorizeCategoryForm'
_title: 'Categorize'
requirements:
_permission: 'administer news feeds'
aggregator.categorize_feed_form:
path: '/aggregator/sources/{aggregator_feed}/categorize'
defaults:
_form: '\Drupal\aggregator\Form\CategorizeFeedForm'
_title: 'Categorize'
requirements:
_permission: 'administer news feeds'
aggregator.opml_page:
path: '/aggregator/opml/{cid}'
defaults:

View File

@ -8,11 +8,3 @@ services:
plugin.manager.aggregator.processor:
class: Drupal\aggregator\Plugin\AggregatorPluginManager
arguments: [processor, '@container.namespaces', '@cache.cache', '@language_manager']
access_check.aggregator.categories:
class: Drupal\aggregator\Access\CategoriesAccessCheck
arguments: ['@database']
tags:
- { name: access_check }
aggregator.category.storage:
class: Drupal\aggregator\CategoryStorageController
arguments: ['@database']

View File

@ -265,58 +265,5 @@ function aggregator_views_data() {
),
);
$data['aggregator_category_feed']['table']['join'] = array(
'aggregator_item' => array(
'left_field' => 'fid',
'field' => 'fid',
),
);
$data['aggregator_category']['table']['group'] = t('Aggregator category');
$data['aggregator_category']['table']['join'] = array(
'aggregator_item' => array(
'left_table' => 'aggregator_category_feed',
'left_field' => 'cid',
'field' => 'cid',
),
);
$data['aggregator_category']['cid'] = array(
'title' => t('Category ID'),
'help' => t('The unique ID of the aggregator category.'),
'field' => array(
'id' => 'numeric',
),
'argument' => array(
'id' => 'aggregator_category_cid',
'name field' => 'title',
'numeric' => TRUE,
),
'filter' => array(
'id' => 'aggregator_category_cid',
),
'sort' => array(
'id' => 'standard',
),
);
$data['aggregator_category']['title'] = array(
'title' => t('Category'),
'help' => t('The title of the aggregator category.'),
'field' => array(
'id' => 'aggregator_category',
),
'argument' => array(
'id' => 'string',
),
'sort' => array(
'id' => 'standard',
),
'filter' => array(
'id' => 'string',
),
);
return $data;
}

View File

@ -8,4 +8,3 @@ items:
expire: 9676800
source:
list_max: 3
category_selector: checkboxes

View File

@ -36,6 +36,3 @@ aggregator.settings:
list_max:
type: integer
label: 'Number of items shown in listing pages'
category_selector:
type: string
label: 'Select categories using'

View File

@ -125,54 +125,6 @@ display:
empty: { }
relationships: { }
arguments: { }
feed_items_per_category:
display_plugin: feed
id: feed_items_per_category
display_title: 'Feed per category'
position: 2
display_options:
path: aggregator/rss/%
display_description: ''
arguments:
cid:
id: cid
table: aggregator_category
field: cid
relationship: none
group_type: group
admin_label: ''
default_action: 'not found'
exception:
value: all
title_enable: false
title: All
title_enable: false
title: ''
breadcrumb_enable: false
breadcrumb: ''
default_argument_type: fixed
default_argument_options:
argument: ''
default_argument_skip_url: false
summary_options:
base_path: ''
count: true
items_per_page: 25
override: false
summary:
sort_order: asc
number_of_records: 0
format: default_summary
specify_validation: false
validate:
type: none
fail: 'not found'
validate_options: { }
break_phrase: false
not: '0'
plugin_id: aggregator_category_cid
defaults:
arguments: false
feed_items:
display_plugin: feed
id: feed_items

View File

@ -1,52 +0,0 @@
<?php
/**
* @file
* Contains \Drupal\aggregator\Access\CategoriesAccess.
*/
namespace Drupal\aggregator\Access;
use Drupal\Core\Access\StaticAccessCheckInterface;
use Drupal\Core\Database\Connection;
use Drupal\Core\Session\AccountInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Route;
/**
* Provides an access check for aggregator categories routes.
*/
class CategoriesAccessCheck implements StaticAccessCheckInterface {
/**
* The database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected $database;
/**
* Constructs a CategoriesAccessCheck object.
*
* @param \Drupal\Core\Database\Connection
* The database connection.
*/
public function __construct(Connection $database) {
$this->database = $database;
}
/**
* {@inheritdoc}
*/
public function appliesTo() {
return array('_access_aggregator_categories');
}
/**
* {@inheritdoc}
*/
public function access(Route $route, Request $request, AccountInterface $account) {
return $account->hasPermission('access news feeds') && (bool) $this->database->queryRange('SELECT 1 FROM {aggregator_category}', 0, 1)->fetchField() ? static::ALLOW : static::DENY;
}
}

View File

@ -1,135 +0,0 @@
<?php
/**
* @file
* Contains \Drupal\aggregator\CategoryStorageController.
*/
namespace Drupal\aggregator;
use Drupal\Core\Database\Connection;
/**
* Storage controller for aggregator categories.
*/
class CategoryStorageController implements CategoryStorageControllerInterface {
/**
* The database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected $database;
/**
* A cache of loaded categories.
*
* @var \stdClass[]
*/
protected $categories;
/**
* Creates a new CategoryStorageController object.
*
* @param \Drupal\Core\Database\Connection $database
* The database connection.
*/
public function __construct(Connection $database) {
$this->database = $database;
}
/**
* {@inheritdoc}
*/
public function load($cid) {
if (!isset($this->categories[$cid])) {
$this->categories[$cid] = $this->database->query("SELECT * FROM {aggregator_category} WHERE cid = :cid", array(':cid' => $cid))->fetchObject();
}
return $this->categories[$cid];
}
/**
* {@inheritdoc}
*/
public function save($category) {
$cid = $this->database->insert('aggregator_category')
->fields(array(
'title' => $category->title,
'description' => $category->description,
'block' => 5,
))
->execute();
return $cid;
}
/**
* {@inheritdoc}
*/
public function update($category) {
$this->database->merge('aggregator_category')
->key(array('cid' => $category->cid))
->fields(array(
'title' => $category->title,
'description' => $category->description,
))
->execute();
}
/**
* {@inheritdoc}
*/
public function delete($cid) {
$this->database->delete('aggregator_category')
->condition('cid', $cid)
->execute();
}
/**
* {@inheritdoc}
*/
public function isUnique($title, $cid = NULL) {
$query = $this->database->select('aggregator_category', 'ac')
->fields('ac', array('title'))
->condition('title', $title);
if (!empty($cid)) {
$query->condition('cid', $cid, '<>');
}
$rows = $query->execute()->fetchCol();
return (empty($rows));
}
/**
* {@inheritdoc}
*/
public function loadByItem($item_id) {
return $this->database->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));
}
/**
* {@inheritdoc}
*/
public function updateItem($iid, array $cids) {
// Remove all existing category items.
$this->database->delete('aggregator_category_item')
->condition('iid', $iid)
->execute();
// Insert new category items.
if (!empty($cids)) {
$insert = $this->database->insert('aggregator_category_item')
->fields(array('iid', 'cid'));
foreach ($cids as $cid) {
$insert->values(array('iid' => $iid, 'cid' => $cid));
}
$insert->execute();
}
}
/**
* {@inheritdoc}
*/
public function loadAllKeyed() {
return $this->database->query('SELECT c.cid, c.title FROM {aggregator_category} c ORDER BY title')->fetchAllKeyed();
}
}

View File

@ -1,99 +0,0 @@
<?php
/**
* @file
* Contains \Drupal\aggregator\CategoryStorageControllerInterface.
*/
namespace Drupal\aggregator;
/**
* Storage Controller for aggregator categories.
*/
interface CategoryStorageControllerInterface {
/**
* Loads an aggregator category by its unique ID.
*
* @param int $cid
* The unique category ID.
*
* @return stdClass|null
* An object containing all category properties.
*/
public function load($cid);
/**
* Saves an aggregator category.
*
* @param \stdClass $category
* The category to save.
*
* @return int
* The new category ID.
*/
public function save($category);
/**
* Updates and aggregator category.
*
* @param \stdClass $category
* The category.
*/
public function update($category);
/**
* Deletes an aggregator category.
*
* @param int $cid
* The category ID.
*/
public function delete($cid);
/**
* Checks if the category title is unique.
*
* Optionally passes a category ID to exclude, if this check is for an
* existing category.
*
* @param string $title
* The category title.
* @param int $cid
* (optional) The category ID to exclude from the check.
*
* @return bool
* TRUE if the category title is unique, FALSE otherwise.
*/
public function isUnique($title, $cid = NULL);
/**
* Loads aggregator categories for an aggregator item.
*
* @param int $item_id
* The aggregator item ID.
*
* @return array
* An array of objects containing item ID, category ID and title.
*/
public function loadByItem($item_id);
/**
* Updates the categories for an aggregator item.
*
* @param int $iid
* The aggregator item ID.
* @param array $cids
* The category IDs.
*/
public function updateItem($iid, array $cids);
/**
* Loads all categories.
*
* @return array
* An array keyed on cid listing all available categories.
*/
public function loadAllKeyed();
}

View File

@ -10,7 +10,6 @@ namespace Drupal\aggregator\Controller;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\aggregator\CategoryStorageControllerInterface;
use Drupal\aggregator\FeedInterface;
use Drupal\aggregator\ItemInterface;
use Drupal\Core\Database\Connection;
@ -31,24 +30,14 @@ class AggregatorController extends ControllerBase implements ContainerInjectionI
*/
protected $database;
/**
* The category storage controller.
*
* @var \Drupal\aggregator\CategoryStorageControllerInterface
*/
protected $categoryStorage;
/**
* Constructs a \Drupal\aggregator\Controller\AggregatorController object.
*
* @param \Drupal\Core\Database\Connection $database
* The database connection.
* @param \Drupal\aggregator\CategoryStorageControllerInterface $category_storage
* The category storage service.
*/
public function __construct(Connection $database, CategoryStorageControllerInterface $category_storage) {
public function __construct(Connection $database) {
$this->database = $database;
$this->categoryStorage = $category_storage;
}
/**
@ -56,8 +45,7 @@ class AggregatorController extends ControllerBase implements ContainerInjectionI
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('database'),
$container->get('aggregator.category.storage')
$container->get('database')
);
}
@ -96,21 +84,6 @@ class AggregatorController extends ControllerBase implements ContainerInjectionI
return $build;
}
/**
* Displays feed items aggregated in a category.
*
* @param int $cid
* The category id for which to list all of the aggregated items.
*
* @return array
* The render array with list of items for the feed.
*/
public function viewCategory($cid) {
$items = $this->entityManager()->getStorageController('aggregator_item')->loadByCategory($cid);
$build = $this->buildPageList($items);
return $build;
}
/**
* Builds a listing of aggregator feed items.
*
@ -209,75 +182,6 @@ class AggregatorController extends ControllerBase implements ContainerInjectionI
'#empty' => $this->t('No feeds available. <a href="@link">Add feed</a>.', array('@link' => $this->urlGenerator()->generateFromPath('admin/config/services/aggregator/add/feed'))),
);
$result = $this->database->query('SELECT c.cid, c.title, COUNT(ci.iid) as items FROM {aggregator_category} c LEFT JOIN {aggregator_category_item} ci ON c.cid = ci.cid GROUP BY c.cid, c.title ORDER BY title');
$header = array($this->t('Title'), $this->t('Items'), $this->t('Operations'));
$rows = array();
foreach ($result as $category) {
$row = array();
$row[] = l($category->title, "aggregator/categories/$category->cid");
$row[] = format_plural($category->items, '1 item', '@count items');
$links = array();
$links['edit'] = array(
'title' => $this->t('Edit'),
'route_name' => 'aggregator.category_admin_edit',
'route_parameters' => array('cid' => $category->cid),
);
$links['delete'] = array(
'title' => $this->t('Delete'),
'route_name' => 'aggregator.category_delete',
'route_parameters' => array('cid' => $category->cid),
);
$row[] = array(
'data' => array(
'#type' => 'operations',
'#links' => $links,
),
);
$rows[] = $row;
}
$build['categories'] = array(
'#prefix' => '<h3>' . $this->t('Category overview') . '</h3>',
'#theme' => 'table',
'#header' => $header,
'#rows' => $rows,
'#empty' => $this->t('No categories available. <a href="@link">Add category</a>.', array('@link' => $this->urlGenerator()->generateFromPath('admin/config/services/aggregator/add/category'))),
);
return $build;
}
/**
* Displays all the categories used by the Aggregator module.
*
* @return array
* A render array.
*/
public function categories() {
$entity_manager = $this->entityManager();
$result = $this->database->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');
$build = array(
'#type' => 'container',
'#attributes' => array('class' => array('aggregator-wrapper')),
'#sorted' => TRUE,
);
$aggregator_summary_items = $this->config('aggregator.settings')->get('source.list_max');
foreach ($result as $category) {
$summary_items = array();
if ($aggregator_summary_items) {
$items = $entity_manager->getStorageController('aggregator_item')->loadByCategory($category->cid);
if ($items) {
$summary_items = $entity_manager->getViewBuilder('aggregator_item')->viewMultiple($items, 'summary');
}
}
$category->url = $this->urlGenerator()->generateFromPath('aggregator/categories/' . $category->cid);
$build[$category->cid] = array(
'#theme' => 'aggregator_summary_items',
'#summary_items' => $summary_items,
'#source' => $category,
);
}
return $build;
}
@ -340,22 +244,13 @@ class AggregatorController extends ControllerBase implements ContainerInjectionI
}
/**
* Generates an OPML representation of all feeds or feeds by category.
*
* @param int $cid
* (optional) If set, feeds are exported only from a category with this ID.
* Otherwise, all feeds are exported. Defaults to NULL.
* Generates an OPML representation of all feeds.
*
* @return \Symfony\Component\HttpFoundation\Response
* The response containing the OPML.
*/
public function opmlPage($cid = NULL) {
if ($cid) {
$result = $this->database->query('SELECT f.title, f.url FROM {aggregator_feed} f LEFT JOIN {aggregator_category_feed} c on f.fid = c.fid WHERE c.cid = :cid ORDER BY title', array(':cid' => $cid));
}
else {
$result = $this->database->query('SELECT * FROM {aggregator_feed} ORDER BY title');
}
$result = $this->database->query('SELECT * FROM {aggregator_feed} ORDER BY title');
$feeds = $result->fetchAll();
$aggregator_page_opml = array(
@ -384,18 +279,4 @@ class AggregatorController extends ControllerBase implements ContainerInjectionI
return Xss::filter($aggregator_feed->label());
}
/**
* Route title callback.
*
* @param int $cid
* The category ID.
*
* @return string
* The category label.
*/
public function categoryTitle($cid) {
$category = $this->categoryStorage->load($cid);
return Xss::filter($category->title);
}
}

View File

@ -200,7 +200,6 @@ class Feed extends ContentEntityBase implements FeedInterface {
* {@inheritdoc}
*/
public static function preDelete(EntityStorageControllerInterface $storage_controller, array $entities) {
$storage_controller->deleteCategories($entities);
foreach ($entities as $entity) {
// Notify processors to remove stored items.
$manager = \Drupal::service('plugin.manager.aggregator.processor');
@ -227,26 +226,6 @@ class Feed extends ContentEntityBase implements FeedInterface {
}
}
/**
* {@inheritdoc}
*/
public function preSave(EntityStorageControllerInterface $storage_controller) {
parent::preSave($storage_controller);
$storage_controller->deleteCategories(array($this->id() => $this));
}
/**
* {@inheritdoc}
*/
public function postSave(EntityStorageControllerInterface $storage_controller, $update = FALSE) {
parent::postSave($storage_controller, $update);
if (!empty($this->categories)) {
$storage_controller->saveCategories($this, $this->categories);
}
}
/**
* {@inheritdoc}
*/

View File

@ -59,24 +59,6 @@ class Item extends ContentEntityBase implements ItemInterface {
}
}
/**
* {@inheritdoc}
*/
public function postSave(EntityStorageControllerInterface $storage_controller, $update = TRUE) {
parent::postSave($storage_controller, $update);
$storage_controller->saveCategories($this);
}
/**
* {@inheritdoc}
*/
public static function preDelete(EntityStorageControllerInterface $storage_controller, array $entities) {
parent::preDelete($storage_controller, $entities);
$storage_controller->deleteCategories($entities);
}
/**
* {@inheritdoc}
*/

View File

@ -11,7 +11,6 @@ use Drupal\Component\Utility\String;
use Drupal\Core\Entity\ContentEntityFormController;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Language\Language;
use Drupal\aggregator\CategoryStorageControllerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
@ -19,36 +18,6 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
*/
class FeedFormController extends ContentEntityFormController {
/**
* The category storage controller.
*
* @var \Drupal\aggregator\CategoryStorageControllerInterface
*/
protected $categoryStorageController;
/**
* Constructs a FeedForm object.
*
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* The entity manager.
* @param \Drupal\aggregator\CategoryStorageControllerInterface $category_storage_controller
* The category storage controller.
*/
public function __construct(EntityManagerInterface $entity_manager, CategoryStorageControllerInterface $category_storage_controller) {
parent::__construct($entity_manager);
$this->categoryStorageController = $category_storage_controller;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('entity.manager'),
$container->get('aggregator.category.storage')
);
}
/**
* {@inheritdoc}
*/
@ -88,27 +57,6 @@ class FeedFormController extends ContentEntityFormController {
'#description' => $this->t('The length of time between feed updates. Requires a correctly configured <a href="@cron">cron maintenance task</a>.', array('@cron' => url('admin/reports/status'))),
);
// Handling of categories.
$options = array();
$values = array();
$categories = $this->categoryStorageController->loadAllKeyed();
foreach ($categories as $cid => $title) {
$options[$cid] = String::checkPlain($title);
if (!empty($feed->categories) && in_array($cid, array_keys($feed->categories))) {
$values[] = $cid;
}
}
if ($options) {
$form['category'] = array(
'#type' => 'checkboxes',
'#title' => $this->t('Categorize news items'),
'#default_value' => $values,
'#options' => $options,
'#description' => $this->t('New feed items are automatically filed in the checked categories.'),
);
}
return parent::form($form, $form_state, $feed);
}
@ -137,11 +85,6 @@ class FeedFormController extends ContentEntityFormController {
public function save(array $form, array &$form_state) {
$feed = $this->entity;
$insert = (bool) $feed->id();
if (!empty($form_state['values']['category'])) {
// Store category values for post save operations.
// @see \Drupal\Core\Entity\FeedStorageController::postSave()
$feed->categories = $form_state['values']['category'];
}
$feed->save();
if ($insert) {
drupal_set_message($this->t('The feed %feed has been updated.', array('%feed' => $feed->label())));

View File

@ -18,49 +18,6 @@ use Drupal\Core\Entity\FieldableDatabaseStorageController;
*/
class FeedStorageController extends FieldableDatabaseStorageController implements FeedStorageControllerInterface {
/**
* Overrides Drupal\Core\Entity\DataBaseStorageController::attachLoad().
*/
protected function attachLoad(&$queried_entities, $load_revision = FALSE) {
parent::attachLoad($queried_entities, $load_revision);
$this->loadCategories($queried_entities);
}
/**
* {@inheritdoc}
*/
public function loadCategories(array $feeds) {
foreach ($feeds as $feed) {
$feed->categories = $this->database->query('SELECT c.cid, c.title FROM {aggregator_category} c JOIN {aggregator_category_feed} f ON c.cid = f.cid AND f.fid = :fid ORDER BY title', array(':fid' => $feed->id()))->fetchAllKeyed();
}
}
/**
* {@inheritdoc}
*/
public function saveCategories(FeedInterface $feed, array $categories) {
foreach ($categories as $cid => $value) {
if ($value) {
$this->database->insert('aggregator_category_feed')
->fields(array(
'fid' => $feed->id(),
'cid' => $cid,
))
->execute();
}
}
}
/**
* {@inheritdoc}
*/
public function deleteCategories(array $feeds) {
// An existing feed is being modified, delete the category listings.
$this->database->delete('aggregator_category_feed')
->condition('fid', array_keys($feeds))
->execute();
}
/**
* {@inheritdoc}
*/

View File

@ -15,33 +15,6 @@ use Drupal\Core\Entity\EntityStorageControllerInterface;
*/
interface FeedStorageControllerInterface extends EntityStorageControllerInterface {
/**
* Loads the categories of a feed.
*
* @param array $feeds
* A list of feed entities keyed by feed id. Each entity will get a
* categories property added.
*/
public function loadCategories(array $feeds);
/**
* Saves the categories of a feed.
*
* @param \Drupal\aggregator\Entity\FeedInterface $feed
* The feed entity.
* @param array $categories
* The array of categories.
*/
public function saveCategories(FeedInterface $feed, array $categories);
/**
* Deletes the categories of a feed.
*
* @param array $feeds
* A list of feed entities keyed by feed id.
*/
public function deleteCategories(array $feeds);
/**
* Provides a list of duplicate feeds.
*

View File

@ -1,147 +0,0 @@
<?php
/**
* @file
* Contains \Drupal\aggregator\Form\AggregatorCategorizeFormBase.
*/
namespace Drupal\aggregator\Form;
use Drupal\aggregator\CategoryStorageControllerInterface;
use Drupal\aggregator\FeedInterface;
use Drupal\aggregator\ItemStorageControllerInterface;
use Drupal\Component\Utility\String;
use Drupal\Core\Entity\EntityViewBuilderInterface;
use Drupal\Core\Form\FormBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides a base form to allow items to be categorized.
*/
abstract class AggregatorCategorizeFormBase extends FormBase {
/**
* The aggregator item view builder.
*
* @var \Drupal\Core\Entity\EntityViewBuilderInterface
*/
protected $aggregatorItemRenderer;
/**
* The aggregator config.
*
* @var \Drupal\Core\Config\Config
*/
protected $config;
/**
* The aggregator item storage controller.
*
* @var \Drupal\aggregator\ItemStorageControllerInterface
*/
protected $aggregatorItemStorage;
/**
* The aggregator category storage controller.
*
* @var \Drupal\aggregator\CategoryStorageControllerInterface
*/
protected $categoryStorage;
/**
* The feed to use.
*
* @var \Drupal\aggregator\FeedInterface
*/
protected $feed;
/**
* Constructs a \Drupal\aggregator\Controller\AggregatorController object.
*
* @param \Drupal\Core\Entity\EntityViewBuilderInterface $aggregator_item_renderer
* The item view builder.
* @param \Drupal\aggregator\ItemStorageControllerInterface $aggregator_item_storage
* The aggregator item storage controller.
* @param \Drupal\aggregator\CategoryStorageControllerInterface $category_storage
* The category storage controller.
*/
public function __construct(EntityViewBuilderInterface $aggregator_item_renderer, ItemStorageControllerInterface $aggregator_item_storage, CategoryStorageControllerInterface $category_storage) {
$this->aggregatorItemRenderer = $aggregator_item_renderer;
$this->config = $this->config('aggregator.settings');
$this->aggregatorItemStorage = $aggregator_item_storage;
$this->categoryStorage = $category_storage;
}
public static function create(ContainerInterface $container) {
return new static(
$container->get('entity.manager')->getViewBuilder('aggregator_item'),
$container->get('entity.manager')->getStorageController('aggregator_item'),
$container->get('aggregator.category.storage')
);
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, array &$form_state, array $items = NULL) {
$form['feed_source'] = array(
'#value' => $this->feed,
);
$categories = array();
$done = FALSE;
$form['items'] = array(
'#type' => 'table',
'#header' => array('', $this->t('Categorize')),
);
if ($items && ($form_items = $this->aggregatorItemRenderer->viewMultiple($items, 'default'))) {
foreach (element_children($form_items) as $iid) {
$categories_result = $this->categoryStorage->loadByItem($iid);
$selected = array();
foreach ($categories_result as $category) {
if (!$done) {
$categories[$category->cid] = String::checkPlain($category->title);
}
if ($category->iid) {
$selected[] = $category->cid;
}
}
$done = TRUE;
$form['items'][$iid]['item'] = $form_items[$iid];
$form['items'][$iid]['categories'] = array(
'#type' => $this->config->get('source.category_selector'),
'#default_value' => $selected,
'#options' => $categories,
'#size' => 10,
'#multiple' => TRUE,
'#parents' => array('categories', $iid),
);
}
}
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Save categories'),
);
$form['pager'] = array('#theme' => 'pager');
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, array &$form_state) {
if (!empty($form_state['values']['categories'])) {
foreach ($form_state['values']['categories'] as $iid => $cids) {
$this->categoryStorage->updateItem($iid, $cids);
}
}
drupal_set_message($this->t('The categories have been saved.'));
}
}

View File

@ -1,30 +0,0 @@
<?php
/**
* @file
* Contains Drupal\aggregator\Form\CategorizeCategoryForm
*/
namespace Drupal\aggregator\Form;
/**
* A form for categorizing feed items in a feed category.
*/
class CategorizeCategoryForm extends AggregatorCategorizeFormBase {
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'aggregator_page_category_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, array &$form_state, $cid = NULL) {
$items = $this->aggregatorItemStorage->loadByCategory($cid);
return parent::buildForm($form, $form_state, $items);
}
}

View File

@ -1,33 +0,0 @@
<?php
/**
* @file
* Contains Drupal\aggregator\Form\CategorizeFeedForm
*/
namespace Drupal\aggregator\Form;
use Drupal\aggregator\FeedInterface;
/**
* A form for categorizing feed items from a feed.
*/
class CategorizeFeedForm extends AggregatorCategorizeFormBase {
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'aggregator_page_source_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, array &$form_state, FeedInterface $aggregator_feed = NULL) {
$this->feed = $aggregator_feed;
$items = $this->aggregatorItemStorage->loadByFeed($aggregator_feed->id());
return parent::buildForm($form, $form_state, $items);
}
}

View File

@ -1,208 +0,0 @@
<?php
/**
* @file
* Contains Drupal\aggregator\Form\CategoryAdminForm.
*/
namespace Drupal\aggregator\Form;
use Drupal\aggregator\CategoryStorageControllerInterface;
use Drupal\block\Plugin\Type\BlockManager;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\FormBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides a form for configuring aggregator categories.
*/
class CategoryAdminForm extends FormBase {
/**
* The module handler.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* The category storage controller.
*
* @var \Drupal\aggregator\CategoryStorageControllerInterface.
*/
protected $categoryStorageController;
/**
* The block manager.
*
* @var \Drupal\block\Plugin\Type\BlockManager
*/
protected $blockManager;
/**
* Creates a new CategoryForm object.
*
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
* @param \Drupal\aggregator\CategoryStorageControllerInterface $category_storage_controller
* The category storage controller.
* @param \Drupal\block\Plugin\Type\BlockManager $block_manager
* (optional) The block manager. Used if block module is enabled.
*/
public function __construct(ModuleHandlerInterface $module_handler, CategoryStorageControllerInterface $category_storage_controller, BlockManager $block_manager = NULL) {
$this->moduleHandler = $module_handler;
$this->categoryStorageController = $category_storage_controller;
$this->blockManager = $block_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
$block_manager = NULL;
if ($container->get('module_handler')->moduleExists('block')) {
$block_manager = $container->get('plugin.manager.block');
}
return new static(
$container->get('module_handler'),
$container->get('aggregator.category.storage'),
$block_manager
);
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'aggregator_form_category';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, array &$form_state, $cid = NULL) {
$category = $this->categoryStorageController->load($cid);
$form['title'] = array(
'#type' => 'textfield',
'#title' => $this->t('Title'),
'#default_value' => isset($category->title) ? $category->title : '',
'#maxlength' => 64,
'#required' => TRUE,
);
$form['description'] = array(
'#type' => 'textarea',
'#title' => $this->t('Description'),
'#default_value' => isset($category->description) ? $category->description : '',
);
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => $this->t('Save'),
);
if (!empty($category->cid)) {
$form['actions']['delete'] = array(
'#type' => 'submit',
'#value' => $this->t('Delete'),
);
$form['cid'] = array('#type' => 'hidden', '#value' => $category->cid);
}
return $form;
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, array &$form_state) {
if ($form_state['values']['op'] == $this->t('Save')) {
// Check for duplicate titles.
$title = $form_state['values']['title'];
if (isset($form_state['values']['cid'])) {
// Exclude the current category ID when checking if it's unique.
$unique = $this->categoryStorageController->isUnique($title, $form_state['values']['cid']);
}
else {
$unique = $this->categoryStorageController->isUnique($title);
}
if (!$unique) {
form_set_error('title', $form_state, $this->t('A category named %category already exists. Enter a unique title.', array('%category' => $title)));
}
}
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, array &$form_state) {
// @todo Replicate this cache invalidation when these ops are separated.
// Invalidate the block cache to update aggregator category-based derivatives.
$this->clearBlockCache();
$link_path = 'aggregator/categories/';
$title = $form_state['values']['title'];
// Redirect to a confirm delete form.
if ($form_state['values']['op'] == $this->t('Delete')) {
$cid = $form_state['values']['cid'];
$form_state['redirect_route'] = array(
'route_name' => 'aggregator.category_delete',
'route_parameters' => array('cid' => $cid),
);
return;
}
// Update the category.
if (!empty($form_state['values']['cid'])) {
$cid = $form_state['values']['cid'];
$this->categoryStorageController->update((object) $form_state['values']);
drupal_set_message($this->t('The category %category has been updated.', array('%category' => $title)));
if (preg_match('/^\/admin/', $this->getRequest()->getPathInfo())) {
$form_state['redirect_route']['route_name'] = 'aggregator.admin_overview';
}
else {
$form_state['redirect_route'] = array(
'route_name' => 'aggregator.category_view',
'route_parameters' => array('cid' => $cid),
);
}
$this->updateMenuLink('update', $link_path . $cid, $title);
return;
}
// Insert the category.
$cid = $this->categoryStorageController->save((object) $form_state['values']);
watchdog('aggregator', 'Category %category added.', array('%category' => $form_state['values']['title']), WATCHDOG_NOTICE, l($this->t('view'), 'admin/config/services/aggregator'));
drupal_set_message($this->t('The category %category has been added.', array('%category' => $title)));
$this->updateMenuLink('insert', $link_path . $cid, $title);
}
/**
* Clear the block cached definitions.
*/
protected function clearBlockCache() {
if (!empty($this->blockManager)) {
$this->blockManager->clearCachedDefinitions();
}
}
/**
* Updates a category menu link.
*
* @param string $op
* The operation to perform.
* @param string $link_path
* The path of the menu link.
* @param string $title
* The title of the menu link.
*
* @see menu_link_maintain()
*/
protected function updateMenuLink($op, $link_path, $title) {
if (isset($op) && $this->moduleHandler->moduleExists('menu_link')) {
menu_link_maintain('aggregator', $op, $link_path, $title);
}
}
}

View File

@ -1,192 +0,0 @@
<?php
/**
* @file
* Contains \Drupal\aggregator\Form\CategoryDeleteForm.
*/
namespace Drupal\aggregator\Form;
use Drupal\aggregator\CategoryStorageControllerInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\ConfirmFormBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Provides a confirm delete form.
*/
class CategoryDeleteForm extends ConfirmFormBase implements ContainerInjectionInterface {
/**
* The category to be deleted.
*
* @var array
*/
protected $category;
/**
* The module handler.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* The entity manager.
*
* @var \Drupal\Core\Entity\EntityManagerInterface
*/
protected $entityManager;
/**
* The category storage controller.
*
* @var \Drupal\aggregator\CategoryStorageControllerInterface
*/
protected $categoryStorageController;
/**
* Creates a new CategoryDeleteForm.
*
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* The entity manager.
* @param CategoryStorageControllerInterface $category_storage_controller
* The category storage controller.
*/
public function __construct(ModuleHandlerInterface $module_handler, EntityManagerInterface $entity_manager, CategoryStorageControllerInterface $category_storage_controller) {
$this->moduleHandler = $module_handler;
$this->entityManager = $entity_manager;
$this->categoryStorageController = $category_storage_controller;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static (
$container->get('module_handler'),
$container->get('entity.manager'),
$container->get('aggregator.category.storage')
);
}
/**
* {@inheritdoc}
*/
public function getQuestion() {
return $this->t('Are you sure you want to delete the category %title?', array('%title' => $this->category->title));
}
/**
* {@inheritdoc}
*/
public function getCancelRoute() {
return array(
'route_name' => 'aggregator.admin_overview',
);
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'aggregator_category_delete';
}
/**
* {@inheritdoc}
*/
public function getConfirmText() {
return $this->t('Delete');
}
/**
* {@inheritdoc}
*/
public function getDescription() {
return $this->t('This will delete the aggregator category, the menu item for this category, and any related category blocks.');
}
/**
* Form constructor.
*
* @param array $form
* An associative array containing the structure of the form.
* @param array $form_state
* An associative array containing the current state of the form.
* @param int|null $cid
* The category ID.
*
* @return array
* The form structure.
*
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
* If the cid param or category is not found.
*/
public function buildForm(array $form, array &$form_state, $cid = NULL) {
$category = $this->categoryStorageController->load($cid);
if (empty($cid) || empty($category)) {
throw new NotFoundHttpException();
}
$this->category = $category;
return parent::buildForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, array &$form_state) {
$cid = $this->category->cid;
$title = $this->category->title;
$this->categoryStorageController->delete($cid);
// Make sure there is no active block for this category.
$this->deleteBlocks($cid);
watchdog('aggregator', 'Category %category deleted.', array('%category' => $title));
drupal_set_message($this->t('The category %category has been deleted.', array('%category' => $title)));
if (preg_match('/^\/admin/', $this->getRequest()->getPathInfo())) {
$form_state['redirect_route']['route_name'] = 'aggregator.admin_overview';
}
else {
$form_state['redirect_route']['route_name'] = 'aggregator.page_last';
}
$this->updateMenuLink('delete', 'aggregator/categories/' . $cid, $title);
}
/**
* Delete aggregator category blocks.
*
* @param int $cid
* The category ID.
*/
protected function deleteBlocks($cid) {
if ($this->moduleHandler->moduleExists('block')) {
foreach ($this->entityManager->getStorageController('block')->loadByProperties(array('plugin' => 'aggregator_category_block:' . $cid)) as $block) {
$block->delete();
}
}
}
/**
* Updates a category menu link.
*
* @param string $op
* The operation to perform.
* @param string $link_path
* The path of the menu link.
* @param string $title
* The title of the menu link.
*
* @see menu_link_maintain()
*/
protected function updateMenuLink($op, $link_path, $title) {
if (isset($op) && $this->moduleHandler->moduleExists('menu_link')) {
menu_link_maintain('aggregator', $op, $link_path, $title);
}
}
}

View File

@ -7,7 +7,6 @@
namespace Drupal\aggregator\Form;
use Drupal\aggregator\CategoryStorageControllerInterface;
use Drupal\aggregator\FeedStorageControllerInterface;
use Drupal\Component\Utility\Url;
use Drupal\Core\Entity\Query\QueryFactory;
@ -43,13 +42,6 @@ class OpmlFeedAdd extends FormBase {
*/
protected $httpClient;
/**
* The category storage controller.
*
* @var \Drupal\aggregator\CategoryStorageControllerInterface
*/
protected $categoryStorageController;
/**
* Constructs a database object.
*
@ -59,14 +51,11 @@ class OpmlFeedAdd extends FormBase {
* The feed storage.
* @param \Guzzle\Http\ClientInterface $http_client
* The Guzzle HTTP client.
* @param \Drupal\aggregator\CategoryStorageControllerInterface $category_storage_controller
* The category storage controller.
*/
public function __construct(QueryFactory $query_factory, FeedStorageControllerInterface $feed_storage, ClientInterface $http_client, CategoryStorageControllerInterface $category_storage_controller) {
public function __construct(QueryFactory $query_factory, FeedStorageControllerInterface $feed_storage, ClientInterface $http_client) {
$this->queryFactory = $query_factory;
$this->feedStorageController = $feed_storage;
$this->httpClient = $http_client;
$this->categoryStorageController = $category_storage_controller;
}
/**
@ -76,8 +65,7 @@ class OpmlFeedAdd extends FormBase {
return new static(
$container->get('entity.query'),
$container->get('entity.manager')->getStorageController('aggregator_feed'),
$container->get('http_default_client'),
$container->get('aggregator.category.storage')
$container->get('http_default_client')
);
}
@ -114,16 +102,6 @@ class OpmlFeedAdd extends FormBase {
'#description' => $this->t('The length of time between feed updates. Requires a correctly configured <a href="@cron">cron maintenance task</a>.', array('@cron' => url('admin/reports/status'))),
);
// Handling of categories.
$options = array_map('check_plain', $this->categoryStorageController->loadAllKeyed());
if ($options) {
$form['category'] = array(
'#type' => 'checkboxes',
'#title' => $this->t('Categorize news items'),
'#options' => $options,
'#description' => $this->t('New feed items are automatically filed in the checked categories.'),
);
}
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array(
'#type' => 'submit',
@ -210,7 +188,6 @@ class OpmlFeedAdd extends FormBase {
'url' => $feed['url'],
'refresh' => $form_state['values']['refresh'],
));
$new_feed->categories = $form_state['values']['category'];
$new_feed->save();
}

View File

@ -20,47 +20,6 @@ use Drupal\Core\Entity\FieldableDatabaseStorageController;
*/
class ItemStorageController extends FieldableDatabaseStorageController implements ItemStorageControllerInterface {
/**
* Overrides Drupal\Core\Entity\DataBaseStorageController::attachLoad().
*/
protected function attachLoad(&$queried_entities, $load_revision = FALSE) {
parent::attachLoad($queried_entities, $load_revision);
$this->loadCategories($queried_entities);
}
/**
* {@inheritdoc}
*/
public function loadCategories(array $entities) {
foreach ($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();
}
}
/**
* {@inheritdoc}
*/
public function deleteCategories(array $entities) {
$this->database->delete('aggregator_category_item')
->condition('iid', array_keys($entities))
->execute();
}
/**
* {@inheritdoc}
*/
public function saveCategories(Item $item) {
$result = $this->database->query('SELECT cid FROM {aggregator_category_feed} WHERE fid = :fid', array(':fid' => $item->getFeedId()));
foreach ($result as $category) {
$this->database->merge('aggregator_category_item')
->key(array(
'iid' => $item->id(),
'cid' => $category->cid,
))
->execute();
}
}
/**
* {@inheritdoc}
*/
@ -82,19 +41,6 @@ class ItemStorageController extends FieldableDatabaseStorageController implement
return $this->executeFeedItemQuery($query, $limit);
}
/**
* {@inheritdoc}
*/
public function loadByCategory($cid, $limit = 20) {
$query = $this->database->select('aggregator_category_item', 'c');
$query->leftJoin('aggregator_item', 'i', 'c.iid = i.iid');
$query->leftJoin('aggregator_feed', 'f', 'i.fid = f.fid');
$query
->fields('i', array('iid'))
->condition('cid', $cid);
return $this->executeFeedItemQuery($query, $limit);
}
/**
* Helper method to execute an item query.
*

View File

@ -15,33 +15,6 @@ use Drupal\core\Entity\EntityStorageControllerInterface;
*/
interface ItemStorageControllerInterface extends EntityStorageControllerInterface {
/**
* Load the categories for aggregator items.
*
* @param array $entities
* An array of aggregator item objects, keyed by the item id. Each object
* will get a categories property added.
*/
public function loadCategories(array $entities);
/**
* Delete the categories for aggregator items.
*
* @param array $entities
* An array of aggregator item objects, keyed by the item id being
* deleted. The storage backend should delete the category data of the
* items.
*/
public function deleteCategories(array $entities);
/**
* Store the categories for aggregator items.
*
* @param Item $item
* The storage backend should save the categories of this item.
*/
public function saveCategories(Item $item);
/**
* Loads feed items from all feeds.
*
@ -66,17 +39,4 @@ interface ItemStorageControllerInterface extends EntityStorageControllerInterfac
*/
public function loadByFeed($fid, $limit = 20);
/**
* Loads feed items from all feeds.
*
* @param int $cid
* The category ID to filter by.
* @param int $limit
* (optional) The number of items to return. Defaults to 20.
*
* @return \Drupal\aggregator\ItemInterface[]
* An array of the feed items.
*/
public function loadByCategory($cid, $limit = 20);
}

View File

@ -1,165 +0,0 @@
<?php
/**
* @file
* Contains \Drupal\aggregator\Plugin\Block\AggregatorCategoryBlock.
*/
namespace Drupal\aggregator\Plugin\Block;
use Drupal\aggregator\CategoryStorageControllerInterface;
use Drupal\block\BlockBase;
use Drupal\block\Annotation\Block;
use Drupal\Core\Annotation\Translation;
use Drupal\Core\Database\Connection;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Session\AccountInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides an 'Aggregator category' block for the latest items in a category.
*
* @Block(
* id = "aggregator_category_block",
* admin_label = @Translation("Aggregator category"),
* category = @Translation("Lists (Views)")
* )
*/
class AggregatorCategoryBlock extends BlockBase implements ContainerFactoryPluginInterface {
/**
* The database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected $connection;
/**
* The category storage controller.
*
* @var \Drupal\aggregator\CategoryStorageControllerInterface
*/
protected $categoryStorageController;
/**
* Constructs an AggregatorFeedBlock 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 array $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Database\Connection $connection
* The database connection.
*/
public function __construct(array $configuration, $plugin_id, array $plugin_definition, Connection $connection, CategoryStorageControllerInterface $category_storage_controller) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->connection = $connection;
$this->categoryStorageController = $category_storage_controller;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('database'),
$container->get('aggregator.category.storage')
);
}
/**
* {@inheritdoc}
*/
public function defaultConfiguration() {
// By default, the block will contain 10 feed items.
return array(
'cid' => 0,
'block_count' => 10,
);
}
/**
* {@inheritdoc}
*/
public function access(AccountInterface $account) {
// Only grant access to users with the 'access news feeds' permission.
return $account->hasPermission('access news feeds');
}
/**
* Overrides \Drupal\block\BlockBase::blockForm().
*/
public function blockForm($form, &$form_state) {
$result = $this->connection->query('SELECT cid, title FROM {aggregator_category} ORDER BY title');
$options = array();
foreach ($result as $category) {
$options[$category->cid] = check_plain($category->title);
}
$form['cid'] = array(
'#type' => 'select',
'#title' => t('Select the category that should be displayed'),
'#default_value' => $this->configuration['cid'],
'#options' => $options,
);
$form['block_count'] = array(
'#type' => 'select',
'#title' => t('Number of news items in block'),
'#default_value' => $this->configuration['block_count'],
'#options' => drupal_map_assoc(range(2, 20)),
);
return $form;
}
/**
* Overrides \Drupal\block\BlockBase::blockSubmit().
*/
public function blockSubmit($form, &$form_state) {
$this->configuration['cid'] = $form_state['values']['cid'];
$this->configuration['block_count'] = $form_state['values']['block_count'];
}
/**
* {@inheritdoc}
*/
public function build() {
$cid = $this->configuration['cid'];
if ($category = $this->categoryStorageController->load($cid)) {
$result = $this->connection->queryRange('SELECT i.* FROM {aggregator_category_item} ci LEFT JOIN {aggregator_item} i ON ci.iid = i.iid WHERE ci.cid = :cid ORDER BY i.timestamp DESC, i.iid DESC', 0, $this->configuration['block_count'], array(':cid' => $category->cid));
$more_link = array(
'#theme' => 'more_link',
'#url' => 'aggregator/categories/' . $category->cid,
'#title' => t("View this category's recent news."),
);
$read_more = drupal_render($more_link);
$items = array();
foreach ($result as $item) {
$aggregator_block_item = array(
'#theme' => 'aggregator_block_item',
'#item' => $item,
);
$items[] = drupal_render($aggregator_block_item);
}
// Only display the block if there are items to show.
if (count($items) > 0) {
$item_list = array(
'#theme' => 'item_list',
'#items' => $items,
);
return array(
'#children' => drupal_render($item_list) . $read_more,
);
}
return array();
}
}
}

View File

@ -105,14 +105,6 @@ class DefaultProcessor extends AggregatorPluginSettingsBase implements Processor
'#description' => t('Requires a correctly configured <a href="@cron">cron maintenance task</a>.', array('@cron' => url('admin/reports/status'))),
);
$form['processors'][$info['id']]['aggregator_category_selector'] = array(
'#type' => 'radios',
'#title' => t('Select categories using'),
'#default_value' => $this->configuration['source']['category_selector'],
'#options' => array('checkboxes' => t('checkboxes'),
'select' => t('multiple selector')),
'#description' => t('For a small number of categories, checkboxes are easier to use, while a multiple selector works well with large numbers of categories.'),
);
$form['processors'][$info['id']]['aggregator_teaser_length'] = array(
'#type' => 'select',
'#title' => t('Length of trimmed description'),
@ -130,7 +122,6 @@ class DefaultProcessor extends AggregatorPluginSettingsBase implements Processor
$this->configuration['items']['expire'] = $form_state['values']['aggregator_clear'];
$this->configuration['items']['teaser_length'] = $form_state['values']['aggregator_teaser_length'];
$this->configuration['source']['list_max'] = $form_state['values']['aggregator_summary_items'];
$this->configuration['source']['category_selector'] = $form_state['values']['aggregator_category_selector'];
// @todo Refactor aggregator plugins to ConfigEntity so this is not needed.
$this->setConfiguration($this->configuration);
}

View File

@ -1,67 +0,0 @@
<?php
/**
* @file
* Contains \Drupal\aggregator\Plugin\views\argument\CategoryCid.
*/
namespace Drupal\aggregator\Plugin\views\argument;
use Drupal\views\Plugin\views\argument\Numeric;
use Drupal\Component\Annotation\PluginID;
use Drupal\Component\Utility\String;
use Drupal\Core\Database\Connection;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Argument handler to accept an aggregator category id.
*
* @ingroup views_argument_handlers
*
* @PluginID("aggregator_category_cid")
*/
class CategoryCid extends Numeric {
/**
* Database Service Object.
*
* @var \Drupal\Core\Database\Connection
*/
protected $database;
/**
* Constructs a Drupal\Component\Plugin\PluginBase 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 array $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Database\Connection $database
* Database Service Object.
*/
public function __construct(array $configuration, $plugin_id, array $plugin_definition, Connection $database) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->database = $database;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition) {
return new static($configuration, $plugin_id, $plugin_definition, $container->get('database'));
}
/**
* {@inheritdoc}
*/
function titleQuery() {
$titles = $this->database->query("SELECT title FROM {aggregator_category} where cid IN (:cid)", array(':cid' => $this->value))->fetchCol();
return array_map(function ($title) {
return String::checkPlain($title);
}, $titles);
}
}

View File

@ -1,85 +0,0 @@
<?php
/**
* @file
* Contains \Drupal\aggregator\Plugin\views\field\Category.
*/
namespace Drupal\aggregator\Plugin\views\field;
use Drupal\views\Plugin\views\display\DisplayPluginBase;
use Drupal\views\Plugin\views\field\FieldPluginBase;
use Drupal\views\ResultRow;
use Drupal\views\ViewExecutable;
use Drupal\Component\Annotation\PluginID;
/**
* Defines a simple renderer that allows linking to an aggregator category.
*
* @ingroup views_field_handlers
*
* @PluginID("aggregator_category")
*/
class Category extends FieldPluginBase {
/**
* {@inheritdoc}
*/
public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
parent::init($view, $display, $options);
$this->additional_fields['cid'] = 'cid';
}
/**
* {@inheritdoc}
*/
protected function defineOptions() {
$options = parent::defineOptions();
$options['link_to_category'] = array('default' => FALSE);
return $options;
}
/**
* {@inheritdoc}
*/
public function buildOptionsForm(&$form, &$form_state) {
$form['link_to_category'] = array(
'#title' => t('Link this field to its aggregator category page'),
'#description' => t('This will override any other link you have set.'),
'#type' => 'checkbox',
'#default_value' => !empty($this->options['link_to_category']),
);
parent::buildOptionsForm($form, $form_state);
}
/**
* Render whatever the data is as a link to the category.
*
* @param string $data
* The XSS safe string for the link text.
* @param \Drupal\views\ResultRow $values
* The values retrieved from a single row of a view's query result.
*
* @return string
* Returns a string for the link text.
*/
protected function renderLink($data, ResultRow $values) {
$cid = $this->getValue($values, 'cid');
if (!empty($this->options['link_to_category']) && !empty($cid) && $data !== NULL && $data !== '') {
$this->options['alter']['make_link'] = TRUE;
$this->options['alter']['path'] = "aggregator/categories/$cid";
}
return $data;
}
/**
* {@inheritdoc}
*/
public function render(ResultRow $values) {
$value = $this->getValue($values);
return $this->renderLink($this->sanitizeValue($value), $values);
}
}

View File

@ -1,65 +0,0 @@
<?php
/**
* @file
* Contains \Drupal\aggregator\Plugin\views\filter\CategoryCid.
*/
namespace Drupal\aggregator\Plugin\views\filter;
use Drupal\views\Plugin\views\filter\InOperator;
use Drupal\Component\Annotation\PluginID;
/**
* Defines a filter handler that filters by aggregator category cid.
*
* @ingroup views_filter_handlers
*
* @PluginID("aggregator_category_cid")
*/
class CategoryCid extends InOperator {
/**
* Database Service Object.
*
* @var \Drupal\Core\Database\Connection
*/
protected $database;
/**
* Constructs a Drupal\Component\Plugin\PluginBase 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 array $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Database\Connection $database
* Database Service Object.
*/
public function __construct(array $configuration, $plugin_id, array $plugin_definition, Connection $database) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->database = $database;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition) {
return new static($configuration, $plugin_id, $plugin_definition, $container->get('database'));
}
/**
* {@inheritdoc}
*/
function getValueOptions() {
if (isset($this->value_options)) {
return;
}
$this->value_options = array();
$this->value_options = $this->database->query('SELECT cid, title FROM {aggregator_category} ORDER BY title')->fetchAllKeyed();
}
}

View File

@ -33,8 +33,6 @@ class AddFeedTest extends AggregatorTestBase {
$this->drupalGet('aggregator/sources/' . $feed->id());
$this->assertResponse(200, 'Feed source exists.');
$this->assertText($feed->label(), 'Page title');
$this->drupalGet('aggregator/sources/' . $feed->id() . '/categorize');
$this->assertResponse(200, 'Feed categorization page exists.');
$this->assertText($feed->label());
// Delete feed.
@ -62,8 +60,6 @@ class AddFeedTest extends AggregatorTestBase {
$this->drupalGet('aggregator/sources/' . $feed->id());
$this->assertResponse(200, 'Long URL feed source exists.');
$this->assertText($feed->label(), 'Page title');
$this->drupalGet('aggregator/sources/' . $feed->id() . '/categorize');
$this->assertResponse(200, 'Long URL feed categorization page exists.');
$this->assertText($feed->label());
// Delete feeds.

View File

@ -34,7 +34,6 @@ class AggregatorConfigurationTest extends AggregatorTestBase {
'aggregator_allowed_html_tags' => '<a>',
'aggregator_summary_items' => 10,
'aggregator_clear' => 3600,
'aggregator_category_selector' => 'select',
'aggregator_teaser_length' => 200,
'aggregator_fetcher' => 'aggregator_test_fetcher',
'aggregator_parser' => 'aggregator_test_parser',

View File

@ -31,8 +31,6 @@ class AggregatorRenderingTest extends AggregatorTestBase {
/**
* Adds a feed block to the page and checks its links.
*
* @todo Test the category block as well.
*/
public function testBlockLinks() {
// Create feed.

View File

@ -206,37 +206,6 @@ abstract class AggregatorTestBase extends WebTestBase {
$this->assertTrue($count == 0);
}
/**
* Pulls feed categories from {aggregator_category_feed} table.
*
* @param \Drupal\aggregator\Entity\Feed $feed
* Feed object representing the feed.
*/
function getFeedCategories(Feed $feed) {
// add the categories to the feed so we can use them
$result = db_query('SELECT cid FROM {aggregator_category_feed} WHERE fid = :fid', array(':fid' => $feed->id()));
foreach ($result as $category) {
$feed->categories[] = $category->cid;
}
}
/**
* Pulls categories from {aggregator_category} table.
*
* @return array
* An associative array keyed by category ID and values are set to the
* category names.
*/
function getCategories() {
$categories = array();
$result = db_query('SELECT * FROM {aggregator_category}');
foreach ($result as $category) {
$categories[$category->cid] = $category;
}
return $categories;
}
/**
* Checks whether the feed name and URL are unique.
*

View File

@ -1,93 +0,0 @@
<?php
/**
* @file
* Definition of Drupal\aggregator\Tests\CategorizeFeedItemTest.
*/
namespace Drupal\aggregator\Tests;
/**
* Tests categorization functionality in the Aggregator module.
*/
class CategorizeFeedItemTest extends AggregatorTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('block');
public static function getInfo() {
return array(
'name' => 'Categorize feed item functionality',
'description' => 'Test feed item categorization.',
'group' => 'Aggregator'
);
}
/**
* Checks that children of a feed inherit a defined category.
*
* If a feed has a category, make sure that the children inherit that
* categorization.
*/
function testCategorizeFeedItem() {
$this->createSampleNodes();
// Simulate form submission on "admin/config/services/aggregator/add/category".
$edit = array('title' => $this->randomName(10), 'description' => '');
$this->drupalPostForm('admin/config/services/aggregator/add/category', $edit, t('Save'));
$this->assertRaw(t('The category %title has been added.', array('%title' => $edit['title'])), format_string('The category %title has been added.', array('%title' => $edit['title'])));
$category = db_query("SELECT * FROM {aggregator_category} WHERE title = :title", array(':title' => $edit['title']))->fetch();
$this->assertTrue(!empty($category), 'The category found in database.');
$link_path = 'aggregator/categories/' . $category->cid;
$menu_links = entity_load_multiple_by_properties('menu_link', array('link_path' => $link_path));
$this->assertTrue(!empty($menu_links), 'The menu link associated with the category found in database.');
$feed = $this->createFeed();
db_insert('aggregator_category_feed')
->fields(array(
'cid' => $category->cid,
'fid' => $feed->id(),
))
->execute();
$this->updateFeedItems($feed, $this->getDefaultFeedItemCount());
$this->getFeedCategories($feed);
$this->assertTrue(!empty($feed->categories), 'The category found in the feed.');
// For each category of a feed, ensure feed items have that category, too.
if (!empty($feed->categories) && !empty($feed->items)) {
foreach ($feed->categories as $cid) {
$categorized_count = db_select('aggregator_category_item')
->condition('iid', $feed->items, 'IN')
->countQuery()
->execute()
->fetchField();
$this->assertEqual($feed->item_count, $categorized_count, 'Total items in feed equal to the total categorized feed items in database');
}
}
// Place a category block.
$block = $this->drupalPlaceBlock("aggregator_category_block", array('label' => 'category-' . $category->title));
// Configure the feed that should be displayed.
$block->getPlugin()->setConfigurationValue('cid', $category->cid);
$block->save();
// Visit the frontpage, assert that the block and the feeds are displayed.
$this->drupalGet('');
$this->assertText('category-' . $category->title);
foreach (\Drupal::entityManager()->getStorageController('aggregator_item')->loadMultiple() as $item) {
$this->assertText($item->label());
}
// Delete feed.
$this->deleteFeed($feed);
}
}

View File

@ -1,57 +0,0 @@
<?php
/**
* @file
* Definition of Drupal\aggregator\Tests\CategorizeFeedTest.
*/
namespace Drupal\aggregator\Tests;
/**
* Tests the categorize feed functionality in the Aggregator module.
*/
class CategorizeFeedTest extends AggregatorTestBase {
public static function getInfo() {
return array(
'name' => 'Categorize feed functionality',
'description' => 'Categorize feed test.',
'group' => 'Aggregator'
);
}
/**
* Creates a feed and makes sure you can add more than one category to it.
*/
function testCategorizeFeed() {
// Create 2 categories.
$category_1 = array('title' => $this->randomName(10), 'description' => '');
$this->drupalPostForm('admin/config/services/aggregator/add/category', $category_1, t('Save'));
$this->assertRaw(t('The category %title has been added.', array('%title' => $category_1['title'])), format_string('The category %title has been added.', array('%title' => $category_1['title'])));
$category_2 = array('title' => $this->randomName(10), 'description' => '');
$this->drupalPostForm('admin/config/services/aggregator/add/category', $category_2, t('Save'));
$this->assertRaw(t('The category %title has been added.', array('%title' => $category_2['title'])), format_string('The category %title has been added.', array('%title' => $category_2['title'])));
// Get categories from database.
$categories = $this->getCategories();
// Create a feed and assign 2 categories to it.
$feed = $this->getFeedEditObject();
foreach ($categories as $cid => $category) {
$feed->categories[$cid] = $cid;
}
$feed->save();
$db_fid = db_query("SELECT fid FROM {aggregator_feed} WHERE title = :title AND url = :url", array(':title' => $feed->label(), ':url' => $feed->url->value))->fetchField();
$db_feed = aggregator_feed_load($db_fid);
// Assert the feed has two categories.
$this->assertEqual(count($db_feed->categories), 2, 'Feed has 2 categories');
// Verify the categories overview page is correctly displayed.
$this->drupalGet('aggregator/categories');
$this->assertText($category_1['title']);
$this->assertText($category_2['title']);
}
}

View File

@ -38,16 +38,6 @@ class ImportOpmlTest extends AggregatorTestBase {
* Opens OPML import form.
*/
function openImportForm() {
db_delete('aggregator_category')->execute();
$category = $this->randomName(10);
$cid = db_insert('aggregator_category')
->fields(array(
'title' => $category,
'description' => '',
))
->execute();
// Enable the help block.
$this->drupalPlaceBlock('system_help_block', array('region' => 'help'));
@ -56,7 +46,6 @@ class ImportOpmlTest extends AggregatorTestBase {
$this->assertField('files[upload]', 'Found file upload field.');
$this->assertField('remote', 'Found Remote URL field.');
$this->assertField('refresh', '', 'Found Refresh field.');
$this->assertFieldByName("category[$cid]", $cid, 'Found category field.');
}
/**
@ -103,17 +92,6 @@ class ImportOpmlTest extends AggregatorTestBase {
$this->assertEqual($before, $after, 'No feeds were added during the two last form submissions.');
db_delete('aggregator_feed')->execute();
db_delete('aggregator_category')->execute();
db_delete('aggregator_category_feed')->execute();
$category = $this->randomName(10);
db_insert('aggregator_category')
->fields(array(
'cid' => 1,
'title' => $category,
'description' => '',
))
->execute();
$feeds[0] = $this->getFeedEditArray();
$feeds[1] = $this->getFeedEditArray();
@ -121,7 +99,6 @@ class ImportOpmlTest extends AggregatorTestBase {
$edit = array(
'files[upload]' => $this->getValidOpml($feeds),
'refresh' => '900',
'category[1]' => $category,
);
$this->drupalPostForm('admin/config/services/aggregator/add/opml', $edit, t('Import'));
$this->assertRaw(t('A feed with the URL %url already exists.', array('%url' => $feeds[0]['url'])), 'Verifying that a duplicate URL was identified');
@ -130,19 +107,17 @@ class ImportOpmlTest extends AggregatorTestBase {
$after = db_query('SELECT COUNT(*) FROM {aggregator_feed}')->fetchField();
$this->assertEqual($after, 2, 'Verifying that two distinct feeds were added.');
$feeds_from_db = db_query("SELECT f.title, f.url, f.refresh, cf.cid FROM {aggregator_feed} f LEFT JOIN {aggregator_category_feed} cf ON f.fid = cf.fid");
$refresh = $category = TRUE;
$feeds_from_db = db_query("SELECT title, url, refresh FROM {aggregator_feed}");
$refresh = TRUE;
foreach ($feeds_from_db as $feed) {
$title[$feed->url] = $feed->title;
$url[$feed->title] = $feed->url;
$category = $category && $feed->cid == 1;
$refresh = $refresh && $feed->refresh == 900;
}
$this->assertEqual($title[$feeds[0]['url']], $feeds[0]['title'], 'First feed was added correctly.');
$this->assertEqual($url[$feeds[1]['title']], $feeds[1]['url'], 'Second feed was added correctly.');
$this->assertTrue($refresh, 'Refresh times are correct.');
$this->assertTrue($category, 'Categories are correct.');
}
/**

View File

@ -54,7 +54,7 @@ class IntegrationTest extends ViewUnitTestBase {
protected function setUp() {
parent::setUp();
$this->installSchema('aggregator', array('aggregator_item', 'aggregator_feed', 'aggregator_category_feed', 'aggregator_category', 'aggregator_category_item'));
$this->installSchema('aggregator', array('aggregator_item', 'aggregator_feed'));
ViewTestData::createTestViews(get_class($this), array('aggregator_test_views'));

View File

@ -10,7 +10,6 @@
* - source_title: Title of the remote source.
* - source_date: Date the feed was posted on the remote source.
* - content: Feed item content.
* - categories: Linked categories assigned to the feed.
*
* @see template_preprocess_aggregator_item()
*
@ -34,10 +33,4 @@
{{ content }}
</div>
{% endif %}
{% if categories %}
<div class="feed-item-categories">
{{ 'Categories'|t }}: {{ categories|join(', ') }}
</div>
{% endif %}
</div>

View File

@ -3,13 +3,13 @@
* @file
* Default theme implementation to present feeds as list items.
*
* Each iteration generates a single feed source or category.
* Each iteration generates a single feed source.
*
* Available variables:
* - title: Title of the feed or category.
* - title: Title of the feed.
* - summary_list: Unordered list of linked feed items generated through
* theme_item_list().
* - source_url: URL to the local source or category.
* - source_url: URL to the local source.
*
* @see template_preprocess_aggregator_summary_items()
*

View File

@ -51,29 +51,6 @@ class AggregatorLocalTasksTest extends LocalTaskIntegrationTest {
);
}
/**
* Checks aggregator category tasks.
*
* @dataProvider getAggregatorCategoryRoutes
*/
public function testAggregatorCategoryLocalTasks($route) {
$this->assertLocalTasks($route, array(
0 => array('aggregator.category_view', 'aggregator.categorize_category_form', 'aggregator.category_edit'),
));
;
}
/**
* Provides a list of category routes to test.
*/
public function getAggregatorCategoryRoutes() {
return array(
array('aggregator.category_view'),
array('aggregator.categorize_category_form'),
array('aggregator.category_edit'),
);
}
/**
* Checks aggregator source tasks.
*
@ -81,7 +58,7 @@ class AggregatorLocalTasksTest extends LocalTaskIntegrationTest {
*/
public function testAggregatorSourceLocalTasks($route) {
$this->assertLocalTasks($route, array(
0 => array('aggregator.feed_view', 'aggregator.categorize_feed_form', 'aggregator.feed_configure'),
0 => array('aggregator.feed_view', 'aggregator.feed_configure'),
));
;
}
@ -92,7 +69,6 @@ class AggregatorLocalTasksTest extends LocalTaskIntegrationTest {
public function getAggregatorSourceRoutes() {
return array(
array('aggregator.feed_view'),
array('aggregator.categorize_feed_form'),
array('aggregator.feed_configure'),
);
}