Commit ac9ab3b8 authored by webchick's avatar webchick

Issue #1957312 by ParisLiakos, peximo, Désiré: Use the entity storage...

Issue #1957312 by ParisLiakos, peximo, Désiré: Use the entity storage controller in aggregator module.
parent fe77b995
......@@ -135,12 +135,10 @@ function aggregator_permission() {
* Queues news feeds for updates once their refresh interval has elapsed.
*/
function aggregator_cron() {
$result = db_query('SELECT fid FROM {aggregator_feed} WHERE queued = 0 AND checked + refresh < :time AND refresh <> :never', array(
':time' => REQUEST_TIME,
':never' => AGGREGATOR_CLEAR_NEVER
));
$queue = \Drupal::queue('aggregator_feeds');
foreach ($result->fetchCol() as $fid) {
$result = \Drupal::entityManager()->getStorageController('aggregator_feed')->getFeedIdsToRefresh();
foreach ($result as $fid) {
$feed = aggregator_feed_load($fid);
if ($queue->createItem($feed)) {
// Add timestamp to avoid queueing item more than once.
......@@ -150,10 +148,17 @@ function aggregator_cron() {
}
// Delete queued timestamp after 6 hours assuming the update has failed.
db_update('aggregator_feed')
->fields(array('queued' => 0))
$result = \Drupal::entityQuery('aggregator_feed')
->condition('queued', REQUEST_TIME - (3600 * 6), '<')
->execute();
if ($result) {
$feeds = entity_load_multiple('aggregator_feed', $result);
foreach ($feeds as $feed) {
$feed->setQueuedTime(0);
$feed->save();
}
}
}
/**
......
......@@ -5,7 +5,6 @@
* Preprocessors and theme functions of Aggregator module.
*/
use Drupal\Core\Entity\EntityInterface;
use Drupal\Component\Utility\String;
/**
......@@ -65,7 +64,7 @@ function theme_aggregator_page_opml($variables) {
$output .= "</head>\n";
$output .= "<body>\n";
foreach ($feeds as $feed) {
$output .= '<outline text="' . String::checkPlain($feed->title) . '" xmlUrl="' . check_url($feed->url) . "\" />\n";
$output .= '<outline text="' . String::checkPlain($feed->label()) . '" xmlUrl="' . check_url($feed->getUrl()) . "\" />\n";
}
$output .= "</body>\n";
$output .= "</opml>\n";
......@@ -85,7 +84,7 @@ function theme_aggregator_page_opml($variables) {
* - summary_items: An array of feed items.
*/
function template_preprocess_aggregator_summary_items(&$variables) {
$variables['title'] = String::checkPlain($variables['source'] instanceof EntityInterface ? $variables['source']->label() : $variables['source']->title);
$variables['title'] = String::checkPlain($variables['source']->label());
$summary_items = array();
foreach (element_children($variables['summary_items']) as $key) {
$summary_items[] = $variables['summary_items'][$key];
......@@ -94,7 +93,7 @@ function template_preprocess_aggregator_summary_items(&$variables) {
'#theme' => 'item_list',
'#items' => $summary_items,
);
$variables['source_url'] = $variables['source'] instanceof EntityInterface ? $variables['source']->url->value : $variables['source']->url;
$variables['source_url'] = $variables['source']->getUrl();
}
/**
......@@ -186,6 +185,7 @@ function template_preprocess_aggregator_feed_source(&$variables) {
*/
function template_preprocess_aggregator_block_item(&$variables) {
// Display the external link to the item.
$variables['url'] = check_url($variables['item']->link);
$variables['title'] = String::checkPlain($variables['item']->title);
$item = $variables['item'];
$variables['url'] = check_url($item->getLink());
$variables['title'] = String::checkPlain($item->label());
}
......@@ -10,44 +10,14 @@
use Drupal\Component\Utility\Xss;
use Drupal\Core\Controller\ControllerBase;
use Drupal\aggregator\FeedInterface;
use Drupal\aggregator\ItemInterface;
use Drupal\Core\Database\Connection;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
/**
* Returns responses for aggregator module routes.
*/
class AggregatorController extends ControllerBase {
/**
* The database connection.
*
* @var \Drupal\Core\Database\Connection;
*/
protected $database;
/**
* Constructs a \Drupal\aggregator\Controller\AggregatorController object.
*
* @param \Drupal\Core\Database\Connection $database
* The database connection.
*/
public function __construct(Connection $database) {
$this->database = $database;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('database')
);
}
/**
* Presents the aggregator feed creation form.
*
......@@ -76,7 +46,7 @@ public function viewFeed(FeedInterface $aggregator_feed) {
$feed_source = $entity_manager->getViewBuilder('aggregator_feed')
->view($aggregator_feed, 'default');
// Load aggregator feed item for the particular feed id.
$items = $entity_manager->getStorageController('aggregator_item')->loadByFeed($aggregator_feed->id());
$items = $entity_manager->getStorageController('aggregator_item')->loadByFeed($aggregator_feed->id(), 20);
// Print the feed items.
$build = $this->buildPageList($items, $feed_source);
return $build;
......@@ -135,36 +105,39 @@ public function feedRefresh(FeedInterface $aggregator_feed) {
* A render array as expected by drupal_render().
*/
public function adminOverview() {
$result = $this->database->query('SELECT f.fid, f.title, f.url, f.refresh, f.checked, f.link, f.description, f.hash, f.etag, f.modified, f.image, COUNT(i.iid) AS items FROM {aggregator_feed} f LEFT JOIN {aggregator_item} i ON f.fid = i.fid GROUP BY f.fid, f.title, f.url, f.refresh, f.checked, f.link, f.description, f.hash, f.etag, f.modified, f.image ORDER BY f.title');
$entity_manager = $this->entityManager();
$feeds = $entity_manager->getStorageController('aggregator_feed')
->loadMultiple();
$header = array($this->t('Title'), $this->t('Items'), $this->t('Last update'), $this->t('Next update'), $this->t('Operations'));
$rows = array();
foreach ($result as $feed) {
foreach ($feeds as $feed) {
$row = array();
$row[] = l($feed->title, "aggregator/sources/$feed->fid");
$row[] = format_plural($feed->items, '1 item', '@count items');
$row[] = ($feed->checked ? $this->t('@time ago', array('@time' => format_interval(REQUEST_TIME - $feed->checked))) : $this->t('never'));
$row[] = ($feed->checked && $feed->refresh ? $this->t('%time left', array('%time' => format_interval($feed->checked + $feed->refresh - REQUEST_TIME))) : $this->t('never'));
$links = array();
$row[] = l($feed->label(), "aggregator/sources/" . $feed->id());
$row[] = format_plural($entity_manager->getStorageController('aggregator_item')->getItemCount($feed), '1 item', '@count items');
$last_checked = $feed->getLastCheckedTime();
$refresh_rate = $feed->getRefreshRate();
$row[] = ($last_checked ? $this->t('@time ago', array('@time' => format_interval(REQUEST_TIME - $last_checked))) : $this->t('never'));
$row[] = ($last_checked && $refresh_rate ? $this->t('%time left', array('%time' => format_interval($last_checked + $refresh_rate - REQUEST_TIME))) : $this->t('never'));
$links['edit'] = array(
'title' => $this->t('Edit'),
'route_name' => 'aggregator.feed_configure',
'route_parameters' => array('aggregator_feed' => $feed->fid),
'route_parameters' => array('aggregator_feed' => $feed->id()),
);
$links['delete'] = array(
'title' => $this->t('Delete'),
'route_name' => 'aggregator.feed_delete',
'route_parameters' => array('aggregator_feed' => $feed->fid),
'route_parameters' => array('aggregator_feed' => $feed->id()),
);
$links['delete_items'] = array(
'title' => $this->t('Delete items'),
'route_name' => 'aggregator.feed_items_delete',
'route_parameters' => array('aggregator_feed' => $feed->fid),
'route_parameters' => array('aggregator_feed' => $feed->id()),
);
$links['update'] = array(
'title' => $this->t('Update items'),
'route_name' => 'aggregator.feed_refresh',
'route_parameters' => array('aggregator_feed' => $feed->fid),
'route_parameters' => array('aggregator_feed' => $feed->id()),
);
$row[] = array(
'data' => array(
......@@ -192,7 +165,7 @@ public function adminOverview() {
* The rendered list of items for the feed.
*/
public function pageLast() {
$items = $this->entityManager()->getStorageController('aggregator_item')->loadAll();
$items = $this->entityManager()->getStorageController('aggregator_item')->loadAll(20);
$build = $this->buildPageList($items);
$build['#attached']['drupal_add_feed'][] = array('aggregator/rss', $this->config('system.site')->get('name') . ' ' . $this->t('aggregator'));
return $build;
......@@ -222,7 +195,7 @@ public function sources() {
->get('source.list_max');
if ($aggregator_summary_items) {
$items = $entity_manager->getStorageController('aggregator_item')
->loadByFeed($feed->id());
->loadByFeed($feed->id(), 20);
if ($items) {
$summary_items = $entity_manager->getViewBuilder('aggregator_item')
->viewMultiple($items, 'summary');
......@@ -250,7 +223,9 @@ public function sources() {
* The response containing the OPML.
*/
public function opmlPage() {
$result = $this->database->query('SELECT * FROM {aggregator_feed} ORDER BY title');
$feeds = $this->entityManager()
->getStorageController('aggregator_feed')
->loadMultiple();
$feeds = $result->fetchAll();
$aggregator_page_opml = array(
......
......@@ -70,10 +70,10 @@ public function validate(array $form, array &$form_state) {
$feed_storage_controller = $this->entityManager->getStorageController('aggregator_feed');
$result = $feed_storage_controller->getFeedDuplicates($feed);
foreach ($result as $item) {
if (strcasecmp($item->title, $feed->label()) == 0) {
if (strcasecmp($item->label(), $feed->label()) == 0) {
$this->setFormError('title', $form_state, $this->t('A feed named %feed already exists. Enter a unique title.', array('%feed' => $feed->label())));
}
if (strcasecmp($item->url, $feed->getUrl()) == 0) {
if (strcasecmp($item->getUrl(), $feed->getUrl()) == 0) {
$this->setFormError('url', $form_state, $this->t('A feed with this URL %url already exists. Enter a unique URL.', array('%url' => $feed->getUrl())));
}
}
......
......@@ -22,14 +22,28 @@ class FeedStorageController extends FieldableDatabaseStorageController implement
* {@inheritdoc}
*/
public function getFeedDuplicates(FeedInterface $feed) {
$query = \Drupal::entityQuery('aggregator_feed');
$or_condition = $query->orConditionGroup()
->condition('title', $feed->label())
->condition('url', $feed->getUrl());
$query->condition($or_condition);
if ($feed->id()) {
$query = $this->database->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 {
$query = $this->database->query("SELECT title, url FROM {aggregator_feed} WHERE title = :title OR url = :url", array(':title' => $feed->label(), ':url' => $feed->url->value));
$query->condition('fid', $feed->id(), '<>');
}
return $query->fetchAll();
return $this->loadMultiple($query->execute());
}
/**
* {@inheritdoc}
*/
public function getFeedIdsToRefresh() {
return $this->database->query('SELECT fid FROM {aggregator_feed} WHERE queued = 0 AND checked + refresh < :time AND refresh <> :never', array(
':time' => REQUEST_TIME,
':never' => AGGREGATOR_CLEAR_NEVER
))->fetchCol();
}
}
......@@ -26,4 +26,12 @@ interface FeedStorageControllerInterface extends EntityStorageControllerInterfac
*/
public function getFeedDuplicates(FeedInterface $feed);
/**
* Returns the fids of feeds that need to be refreshed.
*
* @return array
* A list of feed ids to be refreshed.
*/
public function getFeedIdsToRefresh();
}
......@@ -8,8 +8,7 @@
namespace Drupal\aggregator;
use Drupal\aggregator\Entity\Item;
use Drupal\Core\Database\Query\PagerSelectExtender;
use Drupal\Core\Database\Query\SelectInterface;
use Drupal\Core\Entity\Query\QueryInterface;
use Drupal\Core\Entity\FieldableDatabaseStorageController;
/**
......@@ -23,44 +22,50 @@ class ItemStorageController extends FieldableDatabaseStorageController implement
/**
* {@inheritdoc}
*/
public function loadAll($limit = 20) {
$query = $this->database->select('aggregator_item', 'i');
$query->join('aggregator_feed', 'f', 'i.fid = f.fid');
$query->fields('i', array('iid'));
public function getItemCount(FeedInterface $feed) {
$query = \Drupal::entityQuery('aggregator_item')
->condition('fid', $feed->id())
->count();
return $query->execute();
}
/**
* {@inheritdoc}
*/
public function loadAll($limit = NULL) {
$query = \Drupal::entityQuery('aggregator_item');
return $this->executeFeedItemQuery($query, $limit);
}
/**
* {@inheritdoc}
*/
public function loadByFeed($fid, $limit = 20) {
$query = $this->database->select('aggregator_item', 'i');
$query
->fields('i', array('iid'))
->condition('i.fid', $fid);
public function loadByFeed($fid, $limit = NULL) {
$query = \Drupal::entityQuery('aggregator_item')
->condition('fid', $fid);
return $this->executeFeedItemQuery($query, $limit);
}
/**
* Helper method to execute an item query.
*
* @param SelectInterface $query
* @param \Drupal\Core\Entity\Query\QueryInterface $query
* The query to execute.
* @param int $limit
* (optional) The number of items to return. Defaults to 20.
* (optional) The number of items to return.
*
* @return \Drupal\aggregator\ItemInterface[]
* An array of the feed items.
*/
protected function executeFeedItemQuery(SelectInterface $query, $limit) {
$result = $query
->extend('Drupal\Core\Database\Query\PagerSelectExtender')
->limit($limit)
->orderBy('i.timestamp', 'DESC')
->orderBy('i.iid', 'DESC')
->execute();
protected function executeFeedItemQuery(QueryInterface $query, $limit) {
$query->sort('timestamp', 'DESC')
->sort('iid', 'DESC');
if (!empty($limit)) {
$query->pager($limit);
}
return $this->loadMultiple($result->fetchCol());
return $this->loadMultiple($query->execute());
}
}
......@@ -15,16 +15,27 @@
*/
interface ItemStorageControllerInterface extends EntityStorageControllerInterface {
/**
* Returns the count of the items in a feed.
*
* @param \Drupal\aggregator\FeedInterface $feed
* The feed entity.
*
* @return int
* The count of items associated with a feed.
*/
public function getItemCount(FeedInterface $feed);
/**
* Loads feed items from all feeds.
*
* @param int $limit
* (optional) The number of items to return. Defaults to 20.
* (optional) The number of items to return. Defaults to unlimited.
*
* @return \Drupal\aggregator\ItemInterface[]
* An array of the feed items.
*/
public function loadAll($limit = 20);
public function loadAll($limit = NULL);
/**
* Loads feed items filtered by a feed.
......@@ -32,11 +43,11 @@ public function loadAll($limit = 20);
* @param int $fid
* The feed ID to filter by.
* @param int $limit
* (optional) The number of items to return. Defaults to 20.
* (optional) The number of items to return. Defaults to unlimited.
*
* @return \Drupal\aggregator\ItemInterface[]
* An array of the feed items.
*/
public function loadByFeed($fid, $limit = 20);
public function loadByFeed($fid, $limit = NULL);
}
......@@ -7,9 +7,10 @@
namespace Drupal\aggregator\Plugin\Block;
use Drupal\aggregator\FeedStorageControllerInterface;
use Drupal\aggregator\ItemStorageControllerInterface;
use Drupal\block\BlockBase;
use Drupal\Core\Database\Connection;
use Drupal\Core\Entity\EntityStorageControllerInterface;
use Drupal\Core\Entity\Query\QueryInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Session\AccountInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
......@@ -28,16 +29,23 @@ class AggregatorFeedBlock extends BlockBase implements ContainerFactoryPluginInt
/**
* The entity storage controller for feeds.
*
* @var \Drupal\Core\Entity\EntityStorageControllerInterface
* @var \Drupal\aggregator\FeedStorageControllerInterface
*/
protected $storageController;
protected $feedStorage;
/**
* The database connection.
* The entity storage controller for items.
*
* @var \Drupal\Core\Database\Connection
* @var \Drupal\aggregator\ItemStorageControllerInterface
*/
protected $connection;
protected $itemStorage;
/**
* The entity query object for feed items.
*
* @var \Drupal\Core\Entity\Query\QueryInterface
*/
protected $itemQuery;
/**
* Constructs an AggregatorFeedBlock object.
......@@ -48,15 +56,18 @@ class AggregatorFeedBlock extends BlockBase implements ContainerFactoryPluginInt
* The plugin_id for the plugin instance.
* @param array $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Entity\EntityStorageControllerInterface $storage_controller
* @param \Drupal\aggregator\FeedStorageControllerInterface $feed_storage
* The entity storage controller for feeds.
* @param \Drupal\Core\Database\Connection $connection
* The database connection.
* @param \Drupal\aggregator\ItemStorageControllerInterface $item_storage
* The entity storage controller for feed items.
* @param \Drupal\Core\Entity\Query\QueryInterface $item_query
* The entity query object for feed items.
*/
public function __construct(array $configuration, $plugin_id, array $plugin_definition, EntityStorageControllerInterface $storage_controller, Connection $connection) {
public function __construct(array $configuration, $plugin_id, array $plugin_definition, FeedStorageControllerInterface $feed_storage, ItemStorageControllerInterface $item_storage, QueryInterface $item_query) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->storageController = $storage_controller;
$this->connection = $connection;
$this->feedStorage = $feed_storage;
$this->itemStorage = $item_storage;
$this->itemQuery = $item_query;
}
......@@ -69,7 +80,8 @@ public static function create(ContainerInterface $container, array $configuratio
$plugin_id,
$plugin_definition,
$container->get('entity.manager')->getStorageController('aggregator_feed'),
$container->get('database')
$container->get('entity.manager')->getStorageController('aggregator_item'),
$container->get('entity.query')->get('aggregator_item')
);
}
......@@ -97,7 +109,7 @@ public function access(AccountInterface $account) {
* Overrides \Drupal\block\BlockBase::blockForm().
*/
public function blockForm($form, &$form_state) {
$feeds = $this->storageController->loadMultiple();
$feeds = $this->feedStorage->loadMultiple();
$options = array();
foreach ($feeds as $feed) {
$options[$feed->id()] = $feed->label();
......@@ -131,27 +143,35 @@ public function blockSubmit($form, &$form_state) {
*/
public function build() {
// Load the selected feed.
if ($feed = $this->storageController->load($this->configuration['feed'])) {
$result = $this->connection->queryRange("SELECT * FROM {aggregator_item} WHERE fid = :fid ORDER BY timestamp DESC, iid DESC", 0, $this->configuration['block_count'], array(':fid' => $feed->id()));
if ($feed = $this->feedStorage->load($this->configuration['feed'])) {
$result = $this->itemQuery
->condition('fid', $feed->id())
->range(0, $this->configuration['block_count'])
->sort('timestamp', 'DESC')
->sort('iid', 'DESC')
->execute();
$items = $this->itemStorage->loadMultiple($result);
$more_link = array(
'#theme' => 'more_link',
'#url' => 'aggregator/sources/' . $feed->id(),
'#title' => t("View this feed's recent news."),
);
$read_more = drupal_render($more_link);
$items = array();
foreach ($result as $item) {
$rendered_items = array();
foreach ($items as $item) {
$aggregator_block_item = array(
'#theme' => 'aggregator_block_item',
'#item' => $item,
);
$items[] = drupal_render($aggregator_block_item);
$rendered_items[] = drupal_render($aggregator_block_item);
}
// Only display the block if there are items to show.
if (count($items) > 0) {
if (count($rendered_items) > 0) {
$item_list = array(
'#theme' => 'item_list',
'#items' => $items,
'#items' => $rendered_items,
);
return array(
'#children' => drupal_render($item_list) . $read_more,
......
......@@ -7,11 +7,13 @@
namespace Drupal\aggregator\Plugin\aggregator\processor;
use Drupal\aggregator\ItemStorageControllerInterface;
use Drupal\aggregator\Plugin\AggregatorPluginSettingsBase;
use Drupal\aggregator\Plugin\ProcessorInterface;
use Drupal\aggregator\FeedInterface;
use Drupal\Core\Database\Database;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\Query\QueryInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
......@@ -35,6 +37,20 @@ class DefaultProcessor extends AggregatorPluginSettingsBase implements Processor
*/
protected $configFactory;
/**
* The entity query object for feed items.
*
* @var \Drupal\Core\Entity\Query\QueryInterface
*/
protected $itemQuery;
/**
* The entity storage controller for items.
*
* @var \Drupal\aggregator\ItemStorageControllerInterface
*/
protected $itemStorage;
/**
* Constructs a DefaultProcessor object.
*
......@@ -46,9 +62,15 @@ class DefaultProcessor extends AggregatorPluginSettingsBase implements Processor
* The plugin implementation definition.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config
* The configuration factory object.
* @param \Drupal\Core\Entity\Query\QueryInterface $item_query
* The entity query object for feed items.
* @param \Drupal\aggregator\ItemStorageControllerInterface $item_storage
* The entity storage controller for feed items.
*/
public function __construct(array $configuration, $plugin_id, array $plugin_definition, ConfigFactoryInterface $config) {
public function __construct(array $configuration, $plugin_id, array $plugin_definition, ConfigFactoryInterface $config, QueryInterface $item_query, ItemStorageControllerInterface $item_storage) {
$this->configFactory = $config;
$this->itemStorage = $item_storage;
$this->itemQuery = $item_query;
// @todo Refactor aggregator plugins to ConfigEntity so merging
// the configuration here is not needed.
parent::__construct($configuration + $this->getConfiguration(), $plugin_id, $plugin_definition);
......@@ -62,7 +84,9 @@ public static function create(ContainerInterface $container, array $configuratio
$configuration,
$plugin_id,
$plugin_definition,
$container->get('config.factory')
$container->get('config.factory'),
$container->get('entity.query')->get('aggregator_item'),
$container->get('entity.manager')->getStorageController('aggregator_item')
);
}
......@@ -194,9 +218,8 @@ public function process(FeedInterface $feed) {
* {@inheritdoc}
*/
public function delete(FeedInterface $feed) {
$iids = Database::getConnection()->query('SELECT iid FROM {aggregator_item} WHERE fid = :fid', array(':fid' => $feed->id()))->fetchCol();
if ($iids) {
entity_delete_multiple('aggregator_item', $iids);
if ($items = $this->itemStorage->loadByFeed($feed->id())) {
$this->itemStorage->delete($items);
}
// @todo This should be moved out to caller with a different message maybe.
drupal_set_message(t('The news items from %site have been deleted.', array('%site' => $feed->label())));
......@@ -213,13 +236,13 @@ public function postProcess(FeedInterface $feed) {
if ($aggregator_clear != AGGREGATOR_CLEAR_NEVER) {
// Delete all items that are older than flush item timer.
$age = REQUEST_TIME - $aggregator_clear;
$iids = Database::getConnection()->query('SELECT iid FROM {aggregator_item} WHERE fid = :fid AND timestamp < :timestamp', array(
':fid' => $feed->id(),
':timestamp' => $age,
))
->fetchCol();
if ($iids) {
entity_delete_multiple('aggregator_item', $iids);
$result = $this->itemQuery
->condition('fid', $feed->id())
->condition('timestamp', $age, '<')
->execute();
if ($result) {
$entities = $this->itemStorage->loadMultiple($result);
$this->itemStorage->delete($entities);
}
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment